C++ 继承方式:公有、保护、私有,到底在控制什么

继承方式不决定基类成员能否使用,而是决定其在派生类中的访问级别。公有继承保持接口与类型关系(is-a),支持多态;保护继承隐藏外部接口但允许家族内访问;私有继承实现复用且断绝上下级关系(has-a)。基类private成员始终不可访问。组合优于私有继承,除非需重写虚函数或访问protected成员。显式声明继承方式,避免默认规则陷阱。

一句话定调:继承方式不决定派生类"能不能用"基类成员,而是决定"基类成员在派生类里被降级到什么访问级别"。

基类成员本身有访问级别:public / protected / private

继承方式也有级别:public / protected / private

最终在派生类中呈现的访问性,取两者中更严格的那个:

复制代码
public   >  protected  >  private

一、核心矩阵

复制代码
class Base {
public:
    int pub;
protected:
    int prot;
private:
    int priv;
};
基类成员 \ 继承方式 public 继承 protected 继承 private 继承
public public protected private
protected protected protected private
private 不可访问 不可访问 不可访问

基类 private成员在任何继承方式下,派生类都不能直接访问------它存在但编译器不让碰。


二、公有继承:is-a,接口继承

复制代码
class Derived : public Base {
    void internal() {
        pub = 1;   // public → public,类内可访问
        prot = 1;  // protected → protected,派生类内部可访问
        // priv = 1; // 编译错误:基类 private 成员,派生类永远不能直接碰
    }
};

类外:

复制代码
Derived d;
d.pub = 1;    // public 成员,类外可访问
// d.prot = 1; // 编译错误:protected 成员,类外禁止访问(protected 语义本身限制,与继承方式无关)

语义:Derived is a Base

复制代码
Base* p = new Derived; // 只有 public 继承支持向上转型

设计含义:基类定义接口契约,派生类提供特化实现,这是多态的基础。


三、保护继承:对外关门,家族内部留接口

复制代码
class Derived : protected Base {
    void internal() {
        pub = 1;   // 降级为 protected,派生类内部可访问
        prot = 1;  // protected → protected
        // priv = 1; // 编译错误:基类 private,不可访问
    }
};

类外:

复制代码
Derived d;
// d.pub = 1; // 编译错误:已降级为 protected,类外不可访问

子孙类仍然可用:

复制代码
class MoreDerived : public Derived {
    void internal() {
        pub = 1;   // 在 Derived 中是 protected,子孙类可访问
        prot = 1;  // protected,子孙类可访问
    }
};

向上转型:

复制代码
// Base* p = new Derived; // 编译错误:protected 继承,类外不允许向上转型

语义:复用 Base 能力,但不承认自己是一个 Base。

适用场景极少,多见于库或框架的中间层基类。


四、私有继承:实现复用,断绝对外和对下的接口暴露

复制代码
class Derived : private Base {
    void internal() {
        pub = 1;   // 降级为 private,派生类内部可访问
        prot = 1;  // 降级为 private
        // priv = 1; // 编译错误:基类 private,不可访问
    }
};

类外:

复制代码
Derived d;
// d.pub = 1; // 编译错误:已降级为 private,类外不可访问

子孙类也拿不到:

复制代码
class MoreDerived : public Derived {
    void internal() {
        // pub = 1;  // 编译错误:在 Derived 中已是 private,子孙类不可访问
    }
};

向上转型:

复制代码
// Base* p = new Derived; // 编译错误:private 继承,类外不允许向上转型

语义:Derived is implemented in terms of Base------不是 is-a,而是"用 Base 实现 Derived"。


五、三种继承方式对照

继承方式 建模关系 类外可访问基类 public 子孙类可访问基类接口 向上转型 Base*
public is-a 可以 可以 允许
protected 家族实现复用 不可以(降级为 protected) 可以 不允许
private 实现复用 不可以(降级为 private) 不可以 不允许

经验法则:

90% 情况用 public 继承。需要 has-a 或实现复用时,先考虑组合,再考虑 private 继承。protected 继承基本只在框架内部出现。


六、组合 vs 私有继承

私有继承能做的事,组合通常也能做且耦合更低:

复制代码
class Stopwatch {
    Timer timer;  // 组合:不引入继承关系,可持有多个,不影响派生类体系
public:
    void begin() { timer.start(); }
    void end()   { timer.stop(); }
};

私有继承仅在以下情况更有价值:

  • 需要重写基类虚函数

  • 需要访问基类 protected 成员

  • 需要 EBO(空基类优化)


七、using 可以有选择地"放出来"

复制代码
class Derived : private Base {
public:
    using Base::pub;  // 将 Base::pub 重新提升为 Derived 的 public 成员
};

限制:只能提升到继承方式允许的级别范围内,不能突破基类成员本身的访问级别。


八、默认继承方式(易踩坑)

复制代码
class Derived : Base {};     // 默认 private 继承
struct Derived : Base {};    // 默认 public 继承

工程规范:始终显式写明继承方式,不依赖默认规则。


九、一句话总结

  • public 继承:保接口、保类型关系,is-a

  • protected 继承:封外部、留家族,半隐藏

  • private 继承:封外部、断子孙,纯实现复用

  • 基类 private 成员:派生类永远不能直接访问

  • 继承方式 = 基类接口在派生类中的再封装策略

相关推荐
longlongzihan1 小时前
LeetCode 56合并区间:排序与贪心
c++·算法·leetcode
AI备忘录1 小时前
(二十二)华为华三锐捷迈普思科 802.1X 端口认证配置命令(网络准入五厂商对照)
运维·服务器·开发语言·网络·安全·华为
坤坤子吖1 小时前
C++11——Lambda、function、bind 与可调用对象
c++·笔记·学习
free-elcmacom1 小时前
手撕 memcpy 和 memmove:从字节级拷贝到内存重叠的终极较量
c语言·开发语言·青少年编程·visual studio code·visual studio
白杨尚青2 小时前
C++入门篇(十一):string(中)——容量与增删改查:一篇吃透所有常用接口(万字详解)
java·开发语言·c++
老歌老听老掉牙2 小时前
旅行商问题:从数学模型到 Python 实战
开发语言·python
CC数分2 小时前
数据可视化入门:用Python把一堆数字变成一张图
开发语言·python·信息可视化·数据分析
java_nnnn2 小时前
JavaEE进阶-JavaScript初识
开发语言·前端·javascript·java-ee·ecmascript
朔北之忘 Clancy2 小时前
2024 CSP-J 第二轮真题解析
c++·算法·青少年编程·noip·csp·信奥赛·noi