标签:virtual 间接 重定义 查找 cte class 语句 作用 ret
派生类的作用域嵌套在其基类的作用域之内,如果一个名字无法在派生类的作用域内无法正确解析,则编译器将继续在外层的基类作用域中寻找该名字的定义。
派生类中能重定义在其直接基类或间接基类中的名字,此时定义在内层作用域(即派生类)的名字将隐藏定义在外层作用域(即基类)的名字。
struct Base{
Base():mem(0){}
protected int mem;
};
struct Derived : Base{
Derived(int i):mem(i){}
int get_mem() {return mem;}
protected int mem; //@ 隐藏基类中的mem
};
可以通过作用域符来访问被隐藏的基类成员:
struct Derived : Base{
int get_base_mem(){return Base::mem;}
//...
};
作用运算符将覆盖掉原有的查找规则,并指示编译器从 Base
类的作用域开始查找 mem
。
注意:
除了覆盖继承而来的虚函数之外,派生类最好不要重用其他定义在基类中的名字。
如果派生类的成员与基类的某个成员同名,则派生类将在其作用域内隐藏该基类成员,即使派生类成员与基类成员的形参列表不一致,基类成员也会被隐藏。
struct Base{
int memfunc();
};
struct Derived : Base{
int memfunc(int);
};
Derived d;Base b;
b.memfunc(); //@ 正确
d.memfunc(10); //@ 正确
d.memfunc(); //@ 错误,参数列表为空的基类成员函数被隐藏
d.Base::memfunc(); //@ 正确
基类和派生类的虚函数接受的实参必须相同,否则就无法通过基类的引用或者指针调用派生类的虚函数。
class Base{
public:
virtual int fun();
};
class D1 : public Base{
public:
int fun(int); //@ 隐藏了Base中的fun函数
virtual void f2();
};
class D2 : public D1{
public:
int fun(int); //@ 隐藏了D1 中的 fun 函数
int fun(); //@ 覆盖了Base 中的 fun 函数
void f2(); //@ 覆盖了 D1 中的 f2 函数
};
Base bobj;D1 d1obj;D2 d2obj;
Base* bp1 = &bobj,*bp2 = &d1obj,*bp3 = &d2obj;
bp1->fun(); //@ 调用Base::fun
bp2->fun(); //@ 调用Base::fun
bp3->fun(); //@ 调用D2::fun
D1 *d1p = &d1obj;D2 *d2p = &d2obj;
bp2->f2(); //@ 错误,Base没有名字为f2的成员
d1p->f2(); //@ 调用D1::f2
d2p->f2(); //@ 调用D2::f2
Base *p1 = &d2obj;D1 *p2 = &d2onj;D2 *p3 = &2dobj;
p1->fun(42); //@ 错误,Base中没有接受一个int的fun
p2->fun(42); //@ 静态绑定,调用D1::fun(int)
p3->fun(42); //@ 静态绑定,调用D2::fun(int)
成员函数无论是否是虚函数,都可以被重载,派生类可以覆盖重载函数的0个或多个实例,如果派生类希望所有的重载版本对它来说都是可见的,那么它就需要覆盖所有的版本,或者一个也不覆盖。
有时候只需要覆盖重载集合中的一个版本,而不得不覆盖基类中的每一个版本,显然很麻烦。一种的好的解决办法是为重载成员提供一条 using
声明语句,这样就不需要覆盖基类中的每一个重载版本。using 声明语句指定了一个名字而不指定形参列表,所以一条基类成员函数的 using
声明语句就能把该函数的所有重载实例添加到派生类的作用域中,此时派生类只需要定义其特有的版本即可,无需为继承而来的。
标签:virtual 间接 重定义 查找 cte class 语句 作用 ret
原文地址:https://www.cnblogs.com/xiaojianliu/p/12496349.html