首页 > 其他 > 详细

虚函数与动态绑定

时间:2014-02-28 12:43:10      阅读:496      评论:0      收藏:0      [点我收藏+]

虚函数进行动态绑定需满足的条件:

1)只有指定为虚函数的成员函数才能进行动态绑定

2)必须通过基类的引用或者指针进行函数调用

即: 动态绑定 = 虚函数+指针/引用传递

源码:

基类代码:

class item_base
{
public:
	//virtual item_base(void); 构造函数不允许成为virtual
	item_base(const string &book = "", double sale_price = 0);
	virtual ~item_base(void);  //类成员可以是虚函数,非类成员不可以
		
	string book() const { return ISBN; }; //希望派生类继承的
	virtual double net_prices(size_t n=1) const; //virtual希望派生类重定义的
	virtual item_base* get_class(){ return this;}; 

	virtual void print(ostream& os) { os << "base class:" << ISBN << endl; };
	int test();

private:
	string ISBN;

protected:  //可以被派生类访问,但不能该类的普通用户访问
	double price;
};
void print_total(ostream& os, const item_base&item, size_t n);
//virtual int fun(); //error 只有类成员可以是虚函数
继承类代码:

class bulk_item: public item_base
{
public:
	bulk_item() { };
	~bulk_item() { };

	string book() const { return ""; }; //希望派生类继承的,设计为非虚函数
	//bulk_item(const string& str): ISBN(str), price(0) { };

	/*virtual*/ double net_prices(size_t n=2) const; //虚函数不加virtual也是虚函数,永远是

	//virtual item_base* get_class() { return this; };
	virtual bulk_item* get_class() { return this; }; //虚函数的继承类成员可以返回派生类类型的指针或者引用
	
	void memfcn(const bulk_item &d, const item_base &b);
	virtual void print(ostream& os) { item_base::print(os); os <<"derived print"<< endl; };

	void print() { print(cout); };

	int test();

private:
	size_t min_qty;
	double discount;
};

注意:

1)虚函数的覆盖机制

在默认情况下,继承类调用虚函数,一般是使用继承类的版本,如何使用基类版本呢??如下调用就可以使用基类版本:

	item_base base("hello");
	bulk_item derived;
	derived.item_base::test();  //调用基类版本
	derived.test();   //调用继承类

2) 虚函数的形参使用默认实参

如果一个调用省略了具体有默认默认值的实参,则所用的值由调用该函数的类型定义,与对象的动态类型无关。如下调用

	base.net_prices(); //调用基类版本
	derived.net_prices(); //调用继承类版本
	derived.item_base::net_prices(); //调用基类版本

这里还不出端倪,再看下面的调用

	print_total(cout, base, 3);
	print_total(cout, derived, 4);
上面调用中我传入了实参,但是为了测试默认实参的作用,我修改了下面函数的调用方式,这里面传过来的实参就没有用了,默认使用函数声明的实参,使用如下:
//net_price使用默认实参,将由调用该函数的类型定义,与对象的动态类型无关
void print_total(ostream& os, const item_base& item, size_t n)
{
	os << "ISBN:" << item.book() << "\tNum sold:" << n  //总是调用基类的book函数,即使继承类也定义了
		<< "\tTotal price:" << item.net_prices() << endl;  //先调用的虚函数,然后才是普通的成员函数
}
另外一个需要注意的就是我在调试这个非类成员函数的时候,发现默认先是进入虚函数net_price,然后才是非虚函数book,这个是<<操作符先调用右边的表达式或者函数!这里两次调用虽然进入的函数不同,一个是基类版本,一个是继承类版本,但是传入的参数都是1,也就是基类的默认实参,看出端倪没?!通俗点讲就是谁离他最近他就使用谁,他不需要关注间接人后面的真家伙但是动态绑定正好跟这不一样或者说是相反的,动态绑定要知道真正的家伙是谁!!

3)函数调用的延伸

看如下的定义

	base.print(cout);
	derived.print(cout);  //会导致无穷递归自己 ,这里进行了修改
	derived.print(); //会调用继承类的print然后无穷递归
	item_base *bp1 = &base;
	item_base &br1 = base;
	item_base *bp2 = &derived;  //动态绑定 与形参使用基类类类型传递是一致的
	item_base &br2 = derived;

这里print的定义在类中已经声明,主要说一下,在继承类中有实参的虚函数继承中,如果不指定基类就会导致无穷递归,也就说使用了如下的方式:

virtual void print(ostream& os) { print(os); os <<"derived print"<< endl; };
无实参的非虚函数调用的是继承类中的虚函数版本,因为当前this指针指向的是bulk_item*。

调用方式如下:

	bp1->print(cout); //调用基类
	br1.print(cout); //调用基类
	bp2->print(cout); //调用继承类 
	br2.print(cout); //调用继承类
这里可以看出引用于指针并无任何区别,关键的是对象本身是什么,这就需要动态运行期间才能确定,由于bp2 br2默认是指向或者绑定于继承类对象,所以在运行期间使用的是继承类版本。
。。。

虚函数与动态绑定,布布扣,bubuko.com

虚函数与动态绑定

原文:http://blog.csdn.net/comwise/article/details/20046869

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!