C++继承中的同名覆盖问题

1、同名覆盖的理论关键:
继承中同名覆盖问题的核心知识点:作用域问题,例子:

int a;
void dosomething(){
	double a;
	cin>>a; //使用double a
}

现象:内层作用域会覆盖外层作用域的同名变量,而无论变量的类型
原因:当编译器遇到a时,首先在local作用域查找该变量,找到则停止向外查找,而无论这个变量的类型,这就是C++名称遮掩规则

2、C++继承中同名覆盖的情形介绍:
a) 一般继承例子:

//.h
class Base{
private:
	int x;
public: 
	virtual void func1() = 0;
	virtual void func2();
}
class Derived: public Base{
public:
	virtual void func1(); //纯虚函数重写后,这样才能实例化。
	void func3();
}

//.cpp
void Derived::func3(){
	func2();
}

Derived继承了Base类,因此继承了Base类的接口与实现,因此可以调用func2()
具体过程为:编译器在void Derived::func3()函数中遇到func2(),首先在该函数内找func2()的定义,接着在类Derived中查找,然后在基类Base中找到func2(),因此给人以派生类继承了基类接口的印象
注:派生类赋值运算符函数实质是由于同名覆盖,然后在该函数内调用基类赋值运算符函数,利用作用域限定符修饰,令编译器到基类中查找

b) 继承中覆盖例子:

//.h
class Base{
private:
	int x;
public: 
	virtual void func1() = 0;
	virtual void func1(int); //两个func1构成重载
	virtual void func2();
	virtual void func2(int); //两个func2构成重载
	void func3();
	void func3(int); //两个func3构成重载
}
class Derived: public Base{
public:
	virtual void func1(); //纯虚函数重写后,这样才能实例化。
	void func3(int,int); //构成同名覆盖
}

//.cpp
Derived d;
d.func1(); //调用派生类Derived中func1。
d.func1(2); //错误,编译器提示Derived类中不存在该函数,因此即使虚函数也被同名覆盖。
d.func2(); //调用基类Base中func2。
d.func2(5); //调用基类Base中func2(int)。都通过作用域查找调用
d.func3(5); //错误,编译器提示Derived类中不存在该函数,因为同名覆盖(无论特征标是否相同)。
d.func3(); //错误,编译器提示Derived类中不存在该函数,因为同名覆盖(无论特征标是否相同)。
d.func3(3,4); //调用派生类Derived中func3(int,int)。

注:
1、派生类void func3();与基类void func3(int);不构成重载,只是覆盖,因为重载的要求为在同一作用域下
2、覆盖只是看不到,不代表不存在。

c) 取消覆盖的方法:
方法1:利用作用域运算符

//.h
class Derived: public Base{
public:
	virtual void func1(); //纯虚函数重写后,这样才能实例化。
	void func3(int a,int b){ Base::func3(a);...} //方式1:作用域运算符
	virtual void func1(int a){Base::func1(a);} // 派生类声明同名函数,函数中调用基类同名函数,这被称为转交函数
}

方法1:利用using声明

//.h
class Derived: public Base{
public:
	using Base::func1; //让基类中名为func1的所有函数都可用,无论特征标是什么
	using Base::func3; //让基类中名为func3的所有函数都可用,无论特征标是什么
	virtual void func1(); //纯虚函数重写后,这样才能实例化。
	void func3(int a,int b){ Base::func3(a);...} //方式1:作用域运算符
}

//.cpp
Derived d;
d.func1(2); //正确,调用基类Base中func1(int)。
d.func3(5); //正确,调用基类Base中func3(int)。
d.func3(); //正确,调用基类Base中func3()。

此时基类函数均可用,使用using声明引入同名的所有函数,无论特征标是什么。

参考资料:

总结:

1、基类与派生类函数间永远不存在重载,因重载要求两函数为同一作用域。
2、派生类出现与基类同名函数时,若基类为virtual,且特征标完全相同,此时为多态情形;
3、即使基类成员函数为虚函数,但派生类特征标与基类不同,仍然为同名覆盖。
4、基类函数不为虚函数,派生类同名,无论特征标是否相同,均为同名覆盖。
5、造成覆盖的原因为编译器查找变量名范围由小到大,找到即停止,不考虑特征标(C++名称遮掩规则)。
6、基类作用域大于派生类作用域。
7、覆盖只是看不到,不代表不存在。
8、为了让派生类中使用基类中被覆盖的函数,可以使用using声明在派生类中引入基类同名的所有函数,无论特征标是什么;也可以利用转交函数,声明同名函数,函数中调用基类同名函数。

  • 10
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值