C++的静态绑定和动态绑定(或称静态联编和动态联编)_C/C++_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > C/C++ > C++的静态绑定和动态绑定(或称静态联编和动态联编)

C++的静态绑定和动态绑定(或称静态联编和动态联编)

 2011/10/13 8:13:48  banxi1988  http://banxi1988.iteye.com  我要评论(0)
  • 摘要:先看两个相似的程序的执行过程及结果:首先是main()方法驱动Cpp文件如下:#include"Test_StaticBinding_DynamicBinding.h"intmain(){Figurefigure;cout<<"Figure的面积是:"<<figure.area()<<endl;Circlecircle(2.0);cout<<"Circle的面积是:"<<circle.area()<<endl
  • 标签:c++
先看两个相似的程序的执行过程及结果:
首先是main()方法驱动Cpp文件如下:
#include "Test_StaticBinding_DynamicBinding.h"

int main() {

	Figure figure;
	cout<<"Figure的面积是: "<<figure.area()<<endl;

	Circle circle(2.0);
	cout<<"Circle的面积是: "<<circle.area()<<endl;

	Rectangle rect(3.0,4.0);
	cout<<"Rectangle的面积是: "<<rect.area()<<endl;

	return 0;
}
/**
 * 输出结果:
 *
 *1.使用静态绑定输出结果:
Figure的面积是: 0
Circle的面积是: 12.56
Rectangle的面积是: 12

 */


上面的代码是静态绑定的.当我们对于上面的代码进行改进时,
因为上面的Figure和Circle以及Rectangle类都有area()方法.并都输出结果.
输出代码大同小异.我们尝试把将其提取作为一个方法出来.即可以达到重构的效果.
重构后在Figure等类所在的头文件中添加如下非类方法:
void printArea(Figure &figure){
	cout<<"面积是: "<<figure.area()<<endl;
}

重构之后的main函数如下:
#include "Test_StaticBinding_DynamicBinding.h"

int main() {

	Figure figure;
	printArea(figure);

	Circle circle(2.0);
	printArea(circle);

	Rectangle rect(3.0,4.0);
	printArea(rect);

	return 0;
}
/**
 * 输出结果:
 2. 使用printArea()函数输出如下:
面积是: 0
面积是: 0
面积是: 0
 */


上面的程序在编译,运行时均没有出错,可是结果不对.
解析就是,编译器的编译时 将函数:
void printArea(Figure &figure);
中的形参firgure所执行的操作静态绑定到Figure类的area()方法上.这样访问的只是从基类中的area()方法.而不是所传递过来实例所在直接类的area()方法.所以输出结果不正确.

解决这个问题办法就是多态,或者是动态绑定,这个动态绑定是在运行时发生的.因此又被称为
运行时多态.
在C++中实现动态绑定要求成员函数用virtual来标记.
此时类的头文件如下:
#ifndef TEST_STATICBINDING_DYNAMICBINDING_H_
#define TEST_STATICBINDING_DYNAMICBINDING_H_
#include"common.h"
const double PI = 3.14;
class Figure{
public:
	Figure(){

	}
	virtual double area()const{
		return 0.0;
	}
};
class Circle:public Figure{
public:
	Circle(double radius){
		_radius = radius;
	}
	virtual double area()const{
		return PI*_radius*_radius;
	}
protected:
	double _radius;
};

class Rectangle:public Figure{
public:
	Rectangle(double length,double width){
		_length = length;
		_width = width;
	}
	virtual double area()const{
		return _length*_width;
	}
private:
	double _length;
	double _width;
};

void printArea(Figure &figure){
	cout<<"面积是: "<<figure.area()<<endl;
}
#endif /* TEST_STATICBINDING_DYNAMICBINDING_H_ */


输出结果如下:
/***
3.使用动态绑定加printArea()方法输出结果如下:
面积是: 0
面积是: 12.56
面积是: 12
**/


上面的重构还有一个问题就是,我们在打印面积时,没有指明是那一个形状(figure)的面积.
为了解决这个问题.我们为每一种形状添加一个属性.即形状名.
当为形状类添加name属性时,
出错一个报错如下:
引用
invalid in-class initialization of static data member of non-integral type ‘std::string’

在下面这个地址有关于这个问题更多的讨论.
http://stackoverflow.com/questions/1563897/c-static-constant-string-class-member

在我的教材中对于静态成员初始化是这样讲的:
引用
必须对静态成员初始化,只有这样编译程序才会为静态数据成员分配一个具体的空间.
静态数据成员不能在类中初始化.必须在类外部初始化,初始化语法如下:
<数据类型><类名>::<静态数据成员名>=<初始值>;


修改之后形状类的头文件如下:
#ifndef TEST_STATICBINDING_DYNAMICBINDING_H_
#define TEST_STATICBINDING_DYNAMICBINDING_H_
#include"common.h"

const double PI = 3.14;
class Figure{
public:
	static string name;
	Figure(){

	}
	virtual double area()const{
		return 0.0;
	}
};
string Figure::name = "Figure";

class Circle:public Figure{
public:
	static string name;
	Circle(double radius){
		_radius = radius;
	}
	virtual double area()const{
		return PI*_radius*_radius;
	}
protected:
	double _radius;
};
string Circle::name = "Circle";

class Rectangle:public Figure{
public:
	static string name;
	Rectangle(double length,double width){
		_length = length;
		_width = width;
	}
	virtual double area()const{
		return _length*_width;
	}
private:
	double _length;
	double _width;
};
string Rectangle::name = "Rectangle";

void printArea(Figure &figure){
	cout<<figure.name<<"面积是: "<<figure.area()<<endl;
}
#endif /* TEST_STATICBINDING_DYNAMICBINDING_H_ */


输出结果如下:
/**
Figure面积是: 0
Figure面积是: 12.56
Figure面积是: 12
**/


这个也就是说figure中的name属性也是静态绑定的.如何让静态属性动态绑定呢?
我尝试着在静态属性的声明当中添加一个virtual关键字.但是编译的时候报错了.
报错如下:
引用member ‘name’ cannot be declared both virtual and static
百度Google了下没有找到解决方案:

不过在这个地址有人问了类似的问题.
地址如下:
http://stackoverflow.com/questions/7227236/can-we-have-a-virtual-static-method-c
解释如下:
引用
No. static means it doesn't need an object to operate on. virtual means the implementation depends on the type of the calling object. For static there is no calling object, so it doesn't make sense to have both static and virtual on the same function .

嗯,说得很有道理.

于是我想着给这个一个属性一个getter然后将getter设置成动态绑定的对吧.
还是有一个错误.我错了,我其实就算用getter这个getter也是一个静态方法啊.
用eclipse生成的getter方法如下:
	static string _name;
    static string getName() const;

我试图在声明这个属性时初始化它但是失败了.
报错如下:
引用ISO C++ forbids initialization of member ‘_name’
哎C++的限制还真多啊?
好吧.我在构造函数中初始化吧.
然后我遇到一个调用同类中无参构造函数的问题如下:
	Rectangle(){
		_name = "Rectangle";
	}
	Rectangle(double length,double width){
		this();//error
		_length = length;
		_width = width;
	}

上面的this()调用是错的.
那如何在C++中调用同类中的无参构造函数呢?
用全名吗?或者还有其它方法?
我只能尝试自己调用了.如下:
	Rectangle(double length,double width){
		Rectangle();//		new (this)Rectangel();
		_length = length;
		_width = width;
	}

编译可以通过.
然后将name的getter设置为virtual的.但是运行结果出人意料之外如下:
Figure面积是: 0
面积是: 12.56
面积是: 12

后面的两个调用了自己的无参构造函数的name属性都没有得到初始化.
难道是因为调用了自己的无参构造函数其实是初始化了另一个对象?Rectange()
生成的对象又到了哪里去了呢? 或者是动态绑定不成功?
然后我在实际调用的有参构造函数中尝试一下.
果然不是动太绑定不成功而是Rectangle()生成的另外的类实例.找不到了.
// Rectangle构造方法改写如下.
	Rectangle(){

	}
	Rectangle(double length,double width){
		Rectangle();//		new (this)Rectangel();
		_name = "Rectangle";
		_length = length;
		_width = width;
	}
/** 结果:
Figure面积是: 0
面积是: 12.56
Rectangle面积是: 12
 **/

现在我们再来尝试下,我前面在网上查找到的一种调用方法.
看下通过new (this)Rectange()方法能成不?
看起来好像能成,因为有了一个(this)来调用了.
确实成了.
测试结果如下:
//修改之后的Circle构造函数:
	Circle(){
		_name = "Circle";
	}
	Circle(double radius){
		new (this)Circle();
		_radius = radius;
	}
/**
运行结果:
Figure面积是: 0
Circle面积是: 12.56
Rectangle面积是: 12
**/


此时类文件如下:
#ifndef TEST_STATICBINDING_DYNAMICBINDING_H_
#define TEST_STATICBINDING_DYNAMICBINDING_H_
#include"common.h"

const double PI = 3.14;
class Figure{
public:
	Figure(){
		_name = "Figure";
	}
    virtual string getName() const{
    	return _name;
    }

	virtual double area()const{
		return 0.0;
	}
private:
	string _name;

};

class Circle:public Figure{
public:
	Circle(){
		_name = "Circle";
	}
	Circle(double radius){
		new (this)Circle();
		_radius = radius;
	}
    virtual string getName() const{
    	return _name;
    }

	virtual double area()const{
		return PI*_radius*_radius;
	}


protected:
	double _radius;
private:
	string _name;

};

class Rectangle:public Figure{
public:
	Rectangle(){

	}
	Rectangle(double length,double width){
		Rectangle();//		new (this)Rectangel();
		_name = "Rectangle";
		_length = length;
		_width = width;
	}

   virtual string getName() const{
    	return _name;
    }

	virtual double area()const{
		return _length*_width;
	}

private:
	double _length;
	double _width;
	string _name;
};

void printArea(Figure &figure){
	cout<<figure.getName()<<"面积是: "<<figure.area()<<endl;
}

#endif /* TEST_STATICBINDING_DYNAMICBINDING_H_ */


总结:C++和Java还是区别挺多的.关于静态绑定,和动态绑定中C++与Java方面的比较见我的下一篇文章.
发表评论
用户名: 匿名