文章目录
- 条款33:避免遮掩继承而来的名称
- 为什么避免遮掩?
- 如何避免遮掩?
- 1. 使用 `using` 声明式
- 2. 使用转交函数 (Forwarding Functions)
- 总结
条款33:避免遮掩继承而来的名称
在 C++ 中,派生类(derived class)内的名称会覆盖基类(base class)内的名称。这种行为通常被称为“遮掩”。在公共继承(public inheritance)中,通常不希望这种遮掩发生,因为它会导致基类的成员变得不可访问,这可能会使代码难以理解和维护。
为什么避免遮掩?
-
名称冲突:当派生类重定义了与基类相同的名称时,基类的成员将变得不可访问。这种现象可能会导致程序中的行为异常或意外错误。
-
降低可维护性:开发者可能不清楚在派生类中覆盖的成员是基类的成员还是派生类新定义的成员,导致理解代码时增加难度。
-
破坏继承契约:公有继承应该表现出“is-a”关系,派生类应作为基类的扩展。如果派生类覆盖了基类的成员,可能会破坏这种继承关系。
如何避免遮掩?
为了让基类中的成员不被遮掩并能够重新访问,可以使用以下方法:
1. 使用 using
声明式
可以使用 using
声明式将基类中的成员引入派生类,使得它们可以被访问。这样,派生类中的名称将不会覆盖基类的名称。
class Base { public:void func() { std::cout << "Base func\n"; } };class Derived : public Base { public:using Base::func; // 引入 Base 中的 func 函数void func(int x) { std::cout << "Derived func " << x << "\n"; } };int main() {Derived d;d.func(); // 调用 Base::funcd.func(10); // 调用 Derived::func }
在上面的例子中,Derived
类通过 using Base::func;
语句引入了基类中的 func()
函数,这样就能同时使用派生类和基类的同名函数。
2. 使用转交函数 (Forwarding Functions)
当派生类中有同名函数时,如果你希望让基类的成员在派生类中保持可访问性,可以在派生类中编写转交函数,将请求转发到基类的实现。
class Base { public:void func() { std::cout << "Base func\n"; } };class Derived : public Base { public:void func() { Base::func(); } // 转交基类的 func };int main() {Derived d;d.func(); // 调用 Base::func }
在这个例子中,Derived
类的 func()
函数将调用 Base::func()
,从而确保基类的成员函数仍然可用。
总结
- 避免遮掩:在公有继承中,派生类不应遮掩基类的成员。如果必须使用同名成员,确保能够访问基类的成员。
- 使用
using
声明式:可以通过using
声明式引入基类成员,避免它们被遮掩。 - 使用转交函数:通过转交函数将基类的成员调用转发到派生类,确保基类的接口仍然可访问。
遵守这一条款,可以提高代码的可读性、可维护性,并减少因遮掩带来的潜在错误。