C++Primer 第551页 覆盖重载的函数

这里所说的如果派生类希望所有的重载版本对于它来说都是可见的,那么它就需要覆盖所有的版本,或者一个也不留是什么意思呢?

实验现象

#include <iostream>
class base {
public:
	virtual int func() {return 0;}
	virtual int func(int i) {return 1;}
};

class D1 : public base {
public:
	int func() { return 2; }
};

class D2 : public D1 {
public:
	int func(int i) { return 3;}
};

int main()
{
	D1 d1;
	D2 d2;
	base *b1 = &d1;
	base *b2 = &d2;
	b1->func(1);
	b2->func();	
	return 0;
}

基类base中有重载函数func的两个版本,D1继承自base,覆盖了func()的版本,D2继承自D1,覆盖了func(int)的版本。

  1. 主函数里使用动态绑定,base指针绑定D1对象,可以使用fun(int)版本,同样base指针绑定D2对象,也可以使用fun()版本。
  2. 如果在D1调用func(int)版本,比如int funcc() {return func(1);},那么会编译报错,显示no
    matching function for call to ‘D1::func(int)’。如果改成int funcc() {return func();}就没错了。
    同理,在D2中使用func()也会报错。
  3. 如果直接用d1调用fun(int)版本,或者直接用d2调用func()版本,编译会报错。错误也是no matching function for call to ‘XXX’
  4. 如果修改类D1和D2,把覆盖的虚函数去掉,如下所示:
class D1 : public base {
public:
	//int func() { return 2; }
};

class D2 : public D1 {
public:
	//int func(int i) { return 3;}
};

那么直接用d1调用不管哪个func版本都不会报错,同理d2也是。

原理

派生类的作用域嵌套在基类的作用域之内。 D1只覆盖了无参版本的func函数,那么D1的作用域之内,func(int)版本的函数就被隐藏了。使用b1调用func(int)函数,编译器首先在D1作用域内找名字func,找到了名字func,就不会继续往外层作用域查找,此时参数不匹配,于是编译器报错。

同样,D1中的funcc()函数调用func(int)函数,也是先从D1作用域开始查找名字func,也只能找到无参版本,找到无参版本后发现参数不匹配,于是报错。

而如果使用动态绑定,即使用指针d1访问func(),查找名字将从静态类型的作用域开始,即从base的作用域开始查找,而base的作用域内两个版本的func都可见(其中无参版本的是被覆盖后的,有int参数的是原始的),所以找到名字func后还会进行参数匹配,不会出现编译错误。

修改类D1和D2,把覆盖的虚函数去掉,那么D1和D2作用域内就没有名字func了,使用b1调用func(int)或者func()函数,都无法在D1作用域内找到函数名,于是在外层作用域中继续寻找,也就是在base作用域中查找,能找到重载的两个版本的函数,接着进行正常的函数匹配,也不会出现编译错误。

而书上所说的using声明符,相当于将base作用域里的几个重载版本的函数都强行加到了里层的D1作用域里,也能解决2和3的问题。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值