1、同名覆盖的理论关键:
继承中同名覆盖问题的核心知识点:作用域问题,例子:
int a;
void dosomething(){
double a;
cin>>a;
}
现象:内层作用域会覆盖外层作用域的同名变量,而无论变量的类型。
原因:当编译器遇到a
时,首先在local作用域查找该变量,找到则停止向外查找,而无论这个变量的类型,这就是C++名称遮掩规则。
2、C++继承中同名覆盖的情形介绍:
a) 一般继承例子:
class Base{
private:
int x;
public:
virtual void func1() = 0;
virtual void func2();
}
class Derived: public Base{
public:
virtual void func1();
void func3();
}
void Derived::func3(){
func2();
}
Derived
继承了Base
类,因此继承了Base
类的接口与实现,因此可以调用func2()
。
具体过程为:编译器在void Derived::func3()
函数中遇到func2()
,首先在该函数内找func2()
的定义,接着在类Derived
中查找,然后在基类Base
中找到func2()
,因此给人以派生类继承了基类接口的印象。
注:派生类赋值运算符函数实质是由于同名覆盖,然后在该函数内调用基类赋值运算符函数,利用作用域限定符修饰,令编译器到基类中查找。
b) 继承中覆盖例子:
class Base{
private:
int x;
public:
virtual void func1() = 0;
virtual void func1(int);
virtual void func2();
virtual void func2(int);
void func3();
void func3(int);
}
class Derived: public Base{
public:
virtual void func1();
void func3(int,int);
}
Derived d;
d.func1();
d.func1(2);
d.func2();
d.func2(5);
d.func3(5);
d.func3();
d.func3(3,4);
注:
1、派生类void func3();
与基类void func3(int);
不构成重载,只是覆盖,因为重载的要求为在同一作用域下。
2、覆盖只是看不到,不代表不存在。
c) 取消覆盖的方法:
方法1:利用作用域运算符
class Derived: public Base{
public:
virtual void func1();
void func3(int a,int b){ Base::func3(a);...}
virtual void func1(int a){Base::func1(a);}
}
方法1:利用using声明
class Derived: public Base{
public:
using Base::func1;
using Base::func3;
virtual void func1();
void func3(int a,int b){ Base::func3(a);...}
}
Derived d;
d.func1(2);
d.func3(5);
d.func3();
此时基类函数均可用,使用using
声明引入同名的所有函数,无论特征标是什么。
参考资料:
- 学习资料1
- 学习资料2
- Effective C++ 条款33:避免遮掩继承而来的名称
总结:
1、基类与派生类函数间永远不存在重载,因重载要求两函数为同一作用域。
2、派生类出现与基类同名函数时,若基类为virtual,且特征标完全相同,此时为多态情形;
3、即使基类成员函数为虚函数,但派生类特征标与基类不同,仍然为同名覆盖。
4、基类函数不为虚函数,派生类同名,无论特征标是否相同,均为同名覆盖。
5、造成覆盖的原因为编译器查找变量名范围由小到大,找到即停止,不考虑特征标(C++名称遮掩规则)。
6、基类作用域大于派生类作用域。
7、覆盖只是看不到,不代表不存在。
8、为了让派生类中使用基类中被覆盖的函数,可以使用using
声明在派生类中引入基类同名的所有函数,无论特征标是什么;也可以利用转交函数,声明同名函数,函数中调用基类同名函数。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)