class Base
{
private:
int x;
public:
virtual void mf1() = 0;
virtual void mf2();
void mf3();
……
};
class Derived: public Base
{
public:
virtual void mf1();
void mf4();
……
}
void Derived::mf4()
{
……
mf2();
……
}
当编译器看到mf4中的mf2,必须估算它指涉(refer to)什么东西。编译器的做法是查找各作用域,看看有没有mf2的声明式。
下面是查找顺序:
1. 查找local作用域(也就是mf4覆盖的作用域)。
2. 查找mf4函数外围作用域,也就是 class Derived 覆盖的作用域。
3. 再往外围移动,查找 class Base 的作用域(本例在 class Base 中找到 mf2)。
4. 查找含有 Base 的 namespace 的作用域。
5. 查找global作用域
因此,这种查找方式会造成“名称遮掩现象”。
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 Test()
{
Derived d;
int x;
……
d.mf1(); // correct 调用Derived::mf1
d.mf1(x); // error Derived::mf1 遮掩了 Base::mf1
d.mf2(); // correct 调用Base::mf2
d.mf3(); // correct 调用Derved::mf3
d.mf3(x); // error Derived::mf3 遮掩了 Base::mf3
}
如上述代码,即使Base和Derived内的函数有不同的参数类型,“名称遮掩”也适用,且无论式virtual或non-virtual一体适用。
然而,is-a关系是public继承的基石,我们几乎总是要推翻这个“名称遮掩行为”
方法一:使用using
为Base中那些原本会被遮掩的每个名称引入一个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; //让Base class内命名为mf1和mf3的所有东西
using Base::mf3; //在Derived作用域内都可见(并且public)
virtual void mf1();
void mf3();
void mf4();
……
}
void Test()
{
Derived d;
int x;
……
d.mf1(); // correct 调用Derived::mf1
d.mf1(x); // correct 调用Base::mf1
d.mf2(); // correct 调用Base::mf2
d.mf3(); // correct 调用Derved::mf3
d.mf3(x); // correct Base::mf3
}
方法二:使用转交函数
假设Derived以private继承Base,而Derived唯一想继承mf1的无参数版本,那么不能使用using,因为用using会使所有同名函数在Derived class中都可见。因此我们采用一个简单的转交函数。
class Base
{
public:
vitual void mf1() = 0;
virtual void mf1(int);
……
};
class Derived: private Base
{
public:
virtual void mf1()
{
Base::mf1();
}
……
};
void Test()
{
Derived d;
int x;
d.mf1(); // correct 调用Derived::mf1
d.mf1(x); // error Base::mf1()被遮掩
}
函数重载,覆盖,隐藏
重载:
- 相同的范围(在同一个类中);
- 函数名字相同;
- 参数不同;
- virtual 关键字可有可无。
覆盖:
- 不同的范围(分别位于派生类与基类);
- 函数名字相同;
- 参数相同;
- 基类函数必须有virtual 关键字。
隐藏:
- 如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。
- 如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual 关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)
参考网站http://www.cnblogs.com/BeyondTechnology/archive/2010/09/20/1831441.html
http://www.cnblogs.com/txwsh1/archive/2008/06/28/1231751.html