Effective C++ 条款33:避免遮掩继承而来的名称

Effective C++ 条款33:避免遮掩继承而来的名称


核心思想派生类中的名称(成员变量、函数名)会遮掩基类中所有同名的名称,即使参数类型或修饰符不同。这会破坏基类接口的继承性,导致客户端代码意外失败。必须显式引入基类名称保持接口完整性。

⚠️ 1. 名称遮掩机制与危害

基本规则

  • 编译器名称查找:由内而外(先派生类后基类)
  • 派生类同名成员立即终止查找(无论参数是否匹配)
  • 遮掩范围包括:重载函数、类型定义、静态成员

代码验证

class Base {
public:
    virtual void func();        // 版本1
    virtual void func(int);     // 版本2
    void func() const;          // 版本3
};

class Derived : public Base {
public:
    void func(); // 遮掩基类所有func版本!
};

Derived d;
d.func();     // ✅ 调用Derived::func()
d.func(42);   // ❌ 错误!Base::func(int)被遮掩
d.func();     // ❌ 错误!Base::func() const被遮掩(const修饰符不同仍被遮掩)

危害分析

  • 违反public继承的"is-a"原则
  • 破坏基类接口契约
  • 客户端代码需了解继承体系细节

🚨 2. 解决方案:显式引入基类名称

方法1:using声明(推荐)

class Derived : public Base {
public:
    using Base::func; // 引入Base所有func重载
    void func() override; // 覆盖无参版本
};

// 验证:
Derived d;
d.func();     // ✅ 调用Derived::func()
d.func(42);   // ✅ 调用Base::func(int)
d.func();     // ✅ 调用Base::func() const(未被覆盖)

方法2:转发函数(私有继承场景)

class PrivateDerived : private Base { 
public:
    // 仅暴露特定版本
    void func(int x) { Base::func(x); } 
};

⚖️ 3. 最佳实践指南
场景推荐方案原因
public继承需完整接口✅ 使用using声明保持基类所有重载可用
私有继承/选择性暴露🔶 转发函数精确控制暴露接口
派生类添加新重载⚠️ 确保基类重载可见防止基类功能被意外隐藏
模板类继承⚠️ 显式使用this->或using模板基类名称依赖查找规则特殊

现代C++增强

// C++11 override关键字(辅助检查)
class Derived : public Base {
public:
    void func() override; // 明确表示覆盖
};

// C++20 使用concept约束(模板场景)
template<typename T>
class SmartDerived : public T {
public:
    using T::interface; // 确保接口可见
    void interface(int) requires std::derived_from<T, Base>;
};

💡 关键设计原则

  1. 理解名称查找顺序

    • 编译器查找顺序:局部作用域 → 派生类 → 基类
    • 找到第一个匹配名称即停止(即使参数不兼容)
  2. public继承必须保持接口完整

    class Shape {
    public:
        virtual void draw(int color = 0) const;
    };
    
    class Circle : public Shape {
    public:
        using Shape::draw; // 关键声明
        void draw() const; // 新重载(不遮掩基类版本)
    };
    
    Circle c;
    c.draw(10); // ✅ 仍可用(无using声明则错误)
    
  3. 私有继承的精准控制

    class Timer {
    public:
        void start();
        void stop(int delay);
    };
    
    class Widget : private Timer { // 实现继承
    public:
        using Timer::start;       // 仅暴露start
        // stop被有意隐藏
    };
    

危险模式重现

class Base {
public:
    virtual void validate();
    virtual void validate(int level);
};

class Derived : public Base {
public:
    void validate() override; // 遮掩Base::validate(int)!
};

Derived d;
d.validate(3); // 编译错误!重要功能被意外禁用

安全重构方案

class Derived : public Base {
public:
    using Base::validate; // 恢复所有重载
    void validate() override; // 只覆盖特定版本
    // 添加新重载(不影响基类)
    void validate(const std::string& rule);
};

// 所有接口均可用:
d.validate();      // Derived::validate()
d.validate(2);     // Base::validate(int)
d.validate("ISO"); // Derived::validate(string)

模板类特例处理

template<class T>
class Stack : public Container<T> {
public:
    // 必须显式引入基类名称
    using Container<T>::size;
    
    void print() {
        std::cout << size(); // 无using声明时,编译器不查找模板基类
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值