C++令人迷惑的隐藏规则(转自林锐的《高质量c-c++编程》)
8.2.2 令人迷惑的隐藏规则
本来仅仅区别重载与覆盖并不算困难,但是C++的隐藏规则使问题复杂性陡然增加。这里“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
(1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。
(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。
因为我也是一个在学习路上的小白,如果有错误的地方,恳请指正,谢谢!
第一个例子:非虚函数的隐藏与重载
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <vector>
#include <string>
using namespace std;
struct Base
{
void func()
{
cout << "func()" << endl;
}
void func(int i) //这里的func是重载关系
{
cout << "func(int)" << endl;
}
};
struct Derived : public Base
{
void func()
{
cout << "Derived::func()" << endl;//参数与基类某个函数一致,隐藏了基类中同名函数以及重载
}
};
struct Derived2 : public Base
{
int func(double i) //参数与基类任意成员函数都不一致,但同样隐藏了基类中同名函数以及重载
{
cout << "Derived2::func()" << endl;
return 0;
}
};
int main() {
Derived d;
Derived2 dd;
d.func(); //调用的Derived::
dd.func(1); //调用的Derived2::func(int)
//结论:如果是非虚函数,那么派生类和基类不管函数参数是否相同,派生类会隐藏基类成员函数
return 0;
}
第二个例子:虚函数的隐藏、覆盖与重载
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <vector>
#include <string>
using namespace std;
struct Base
{
virtual void func()
{
cout << "func()" << endl;
}
void func(int i) //这里的func同样也是重载关系
{
cout << "func(int)" << endl;
}
};
struct Derived : public Base
{
void func() //函数原型相同,默认是虚函数,这里是覆盖了从基类继承过来的func。
{
cout << "Derived::func()" << endl;//参数与基类某个函数一致,隐藏了基类中同名函数以及重载
}
};
struct Derived2 : public Base
{
int func(double i) //函数原型不同,隐藏了基类的func虚函数。
{
cout << "Derived2::func()" << endl;
return 0;
}
};
int main() {
Derived d;
Derived2 dd;
Base &b = d;
//d.func(1); //错误,在Derived中找不到void func(int)这个函数
d.func(); //调用的Derived::func()
//dd.func(); //错误,在Derived2中找不到void func()这个函数
dd.func(1); //调用的Derived2::func(double)
//结论:如果是虚函数,派生类的虚函数和基类中同名函数函数原型相同的话,派生类虚函数会覆盖基类成员函数,同
//时隐藏基类中的同名函数及其他重载
//如果函数原型不同,会创建出一个新的成员函数(而不是覆盖),同时隐藏基类中的同名函数及其他重载
return 0;
}
总结:除了覆盖继承而来的虚函数之外,派生类最好不要重用其他定义在基类中的名字