Effective C++ 条款33 :避免遮掩继承而来的名称
class Base
{
public:
virtual void mf1() = 0;
virtual void mf2();
void mf3();
private:
int x;
};
class Derived : public Base
{
public:
virtual void mf1();
void mf4();
};
void Derived::mf4()
{
//...
mf2();
//...
}
查找规则 :在上述代码中,编译器看到了mf2()
,需要知道它指的是什么东西。编译器的做法是查找各个作用域,看看有没有名为mf2
的声明式。
首先查找local作用域,也就是函数mf4()
内部。如果没有,查找外围作用域,也就是class Derived
范围。如果还是没有找到,
继续向外移动,在class Base
中查找,在这里,编译器查到了一个函数Base::mf2()
,停止查找。假如Base::mf2()
不存在,
查找继续,不出意外应该是进入命名空间的范围内查找,如果还没有,最后进入全局空间,和系统函数一个等级的作用域范围内去查找。
class Base
{
private:
int x;
public:
virtual void mf1() = 0;
virtual void mf1(int);
virtual void mf2();
void mf3();
void mf3(double);
};
class Derived : public Base
{
public:
virtual void mf1();
void mf3();
void mf4();
};
void main()
{
Derived d;
int x;
d.mf1(); //Derived::mf1
d.mf1(x); //error!! Derived::mf1 掩盖了 Base::mf1
d.mf2(); //Base::mf2
d.mf3(); //Derived::mf3
d.mf3(x); //error Derived::mf3 掩盖了 Base::mf3
}
上面的查找规则对virtual
或者non-virtual
都适用。编译器建立这套行为的理由是为了防止在程序库或者框架内建立新的Derived class
时
附带地从疏远的base classes
继承重载函数。这句话比较拗口,简单来说就是如果派生类public继承了基类,但是又不重写那些virtual function
,
包括基类的重载的需函数。那么就违反了派生类和基类的is-a
关系。当然有时候我们并不想继承基类的所有函数。怎么使用方法来解决这个问题?
//使用using来解决
class Base
{
private:
int x;
public:
virtual void mf1() = 0;
virtual void mf1(int);
virtual void mf2();
void mf3();
void mf3(double);
};
class Derived : public Base
{
public:
using Base::mf1;
using Base::mf3;
virtual void mf1();
void mf3();
void mf4();
};
void main()
{
Derived d;
int x;
d.mf1(); //Derived::mf1
d.mf1(x); //没问题 Base::mf1
d.mf2(); //Base::mf2
d.mf3(); //Derived::mf3
d.mf3(x); //没问题Base::mf3
}
上面使用using引入基类的函数,可以避免派生类中覆盖基类的一些函数。从实际上来说,尽量避免这种情况最佳。