条款33:避免遮掩继承而来的名称
1.1 提出问题
- 名称在C++中,实际上与继承无关。它与范围有关。
int x; // 全局变量
void someFunc()
{double x; // 局部变量std::cin >> x; // 读取本地x的新值
}
- 继承里的名称,实际工作的方式是,派生类的作用域嵌套在其基类的作用域内。
//Base的作用域 x、mf1(2)、mf2、mf3(2)
class Base {
private:int x;
public:virtual void mf1() = 0;virtual void mf1(int);virtual void mf2();void mf3();void mf3(double);...
};
//Derived的作用域 mf1、mf3、mf4
class Derived : public Base {
public:virtual void mf1();void mf3();void mf4();...
};//名称隐藏值取决于名称本身
Derived d;
int x;
...
d.mf1(); // 没问题, 调用 Derived::mf1
d.mf1(x); // 错误! Derived::mf1隐藏Base::mf1
d.mf2(); // 没问题, 调用 Base::mf2
d.mf3(); // 没问题, 调用 Derived::mf3
d.mf3(x); // 错误! Derived::mf3隐藏Base::mf3
1.2 解决办法
由于名称掩盖问题,派生类无法使用来自基类的重载函数,一种解决方法是使用using关键字:
//Base的作用域 x、mf1(2)、mf2、mf3(2)
class Base {
private:int x;
public:virtual void mf1() = 0;virtual void mf1(int);virtual void mf2();void mf3();void mf3(double);...
};
//Derived的作用域 mf1(2)、mf3(2)、mf4
class Derived : public Base {
public:using Base::mf1; // 让Base中所有名为mf1和mf3的东西using Base::mf3; // 在Derived的作用域中可见(并且是public)virtual void mf1();void mf3();void mf4();...
};
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
若不想打开函数的全部版本(在private继承时有意义),这时需要一个简单的转发函数:
class Base {
public:virtual void mf1() = 0;virtual void mf1(int);... // as before
};
class Derived : private Base {
public:virtual void mf1(){ // 一个简单的转发函数 Base::mf1();} ...
};
...
Derived d;
int x;
d.mf1(); // 没问题, 调用 Derived::mf1
d.mf1(x); // 错误! Base::mf1() 被隐藏了
1.3 总结
- 派生类中的名称隐藏基类中的名称。在公共继承下,这是不可取的。
- 要使隐藏的名称再次可见,请使用using声明或转发函数。