跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++

C++ 继承详解:面向对象代码复用的核心机制

C++ 继承是面向对象编程实现代码复用的关键机制。详细阐述了继承的基本语法、三种访问权限控制方式(public/protected/private)以及构造析构函数的调用顺序。通过 Person/Student 及员工管理系统的实战案例,演示了如何正确设计基类与派生类,解决多重继承二义性问题,并提供了常见错误排查方案,帮助开发者掌握继承的核心原理与应用技巧。

暖阳发布于 2026/3/22更新于 2026/8/2341 浏览
C++ 继承详解:面向对象代码复用的核心机制

C++ 继承详解:面向对象代码复用的核心机制

在这里插入图片描述

继承是 C++ 面向对象编程的三大特性之一,它允许一个类(派生类)继承另一个类(基类)的属性和行为。这不仅是实现代码复用的关键手段,也是构建可扩展软件架构的基础。通过继承,我们可以在基类已有的功能上扩展新功能,避免重复编写相同的成员变量和函数。

一、继承的核心概念

继承的价值主要体现在两个方面:

  1. 代码复用:减少冗余,降低维护成本。
  2. 功能扩展:在现有逻辑基础上增加特定业务需求。

例如,生活中'学生'和'老师'都属于'人',都有姓名、年龄等属性和吃饭、睡觉等行为。我们可以先定义 Person 基类,再让 Student 和 Teacher 继承 Person,并各自扩展专属功能。

二、继承的基本语法与实现

2.1 语法格式
class 派生类名 : 继承方式 基类名 {
    // 派生类的成员
};
  • 继承方式:决定基类成员在派生类中的访问权限,包括 public、protected、private 三种。
  • 基类名:被继承的类,也叫父类或超类。
  • 派生类名:继承基类的类,也叫子类或衍生类。
2.2 基础实现案例

以 Person 作为基类,Student 作为派生类为例,演示继承的基本用法。

#include <iostream>
#include <string>
using namespace std;

// 基类:人
class Person {
public:
    string name;
    int age;

    void eat() {
        cout << name << " 正在吃饭" << endl;
    }

    void sleep() {
        cout << name << " 正在睡觉" << endl;
    }
};

// 派生类:学生,公有继承 Person
class Student : public Person {
public:
    // 派生类新增属性:学号
    int studentID;

    // 派生类新增方法:学习
    void study() {
        cout << name << " 正在学习,学号:" << studentID << endl;
    }
};

int main() {
    // 创建派生类对象 Student s
    Student s;
    
    // 访问从基类继承的属性
    s.name = "张三";
    s.age = 18;
    
    // 访问派生类自身的属性
    s.studentID = 2024001;
    
    // 调用从基类继承的方法
    s.eat();
    s.sleep();
    
    // 调用派生类自身的方法
    s.study();
    
    return 0;
}

运行结果如下:

张三 正在吃饭
张三 正在睡觉
张三 正在学习,学号:2024001

三、三种继承方式的访问权限控制

继承方式直接影响基类成员在派生类中的访问权限。核心规则是:继承方式不会提升成员的访问权限,只会限制或保持原有权限。

3.1 权限对比表
基类成员权限public 继承protected 继承private 继承
publicpublicprotectedprivate
protectedprotectedprotectedprivate
private不可访问不可访问不可访问

核心注意点:

  1. 基类的 private 成员在派生类中始终不可直接访问,只能通过基类的 public 或 protected 方法间接访问。
  2. 继承方式的限制作用是单向的,派生类无法突破基类的权限限制。
  3. 实际开发中,public 继承是最常用的方式,protected 和 private 继承仅在特定场景使用。
3.2 不同继承方式的代码演示
3.2.1 public 继承演示
#include <iostream>
using namespace std;

class Base {
public:
    int pub;
protected:
    int pro;
private:
    int pri
};

// 公有继承
class PubDerived : public Base {
public:
    void show() {
        pub = 10;      // 合法:public 继承后仍为 public
        pro = 20;      // 合法:public 继承后为 protected
        // pri = 30;   // 非法:基类 private 成员不可访问
    }
};

int main() {
    PubDerived pd;
    pd.pub = 100;    // 合法:类外可访问 public 成员
    // pd.pro = 200; // 非法:protected 成员类外不可访问
    return 0;
}
3.2.2 protected 继承演示
class ProDerived : protected Base {
public:
    void show() {
        pub = 10;      // 合法:protected 继承后为 protected
        pro = 20;      // 合法:protected 继承后仍为 protected
        // pri = 30;   // 非法:基类 private 成员不可访问
    }
};

int main() {
    ProDerived prd;
    // prd.pub = 100; // 非法:protected 继承后 pub 变为 protected,类外不可访问
    return 0;
}
3.2.3 private 继承演示
class PriDerived : private Base {
public:
    void show() {
        pub = 10;      // 合法:private 继承后为 private
        pro = 20;      // 合法:private 继承后为 private
        // pri = 30;   // 非法:基类 private 成员不可访问
    }
};

int main() {
    PriDerived prd;
    // prd.pub = 100; // 非法:private 继承后 pub 变为 private,类外不可访问
    return 0;
}

四、继承中的构造与析构顺序

派生类对象的创建和销毁过程,会涉及基类和派生类的构造函数、析构函数调用,其顺序有严格的规则。

4.1 核心规则
  • 构造顺序:先调用基类的构造函数,再调用派生类的构造函数。
  • 析构顺序:先调用派生类的析构函数,再调用基类的析构函数。

简单记忆:构造先基后派,析构先派后基。

4.2 代码演示:构造与析构顺序
#include <iostream>
using namespace std;

class Person {
public:
    Person() {
        cout << "Person 基类构造函数被调用" << endl;
    }
    ~Person() {
        cout << "Person 基类析构函数被调用" << endl;
    }
};

class Student : public Person {
public:
    Student() {
        cout << "Student 派生类构造函数被调用" << endl;
    }
    ~Student() {
        cout << "Student 派生类析构函数被调用" << endl;
    }
};

int main() {
    // 创建派生类对象 Student s
    Student s;
    // 函数结束时对象销毁,自动调用析构函数
    return 0;
}

运行结果:

Person 基类构造函数被调用
Student 派生类构造函数被调用
Student 派生类析构函数被调用
Person 基类析构函数被调用
4.3 带参数的构造函数继承

当基类只有带参数的构造函数时,派生类必须在初始化列表中显式调用基类的构造函数。

#include <iostream>
#include <string>
using namespace std;

class Person {
public:
    string name;
    int age;

    // 基类带参数构造函数
    Person(string n, int a) {
        name = n;
        age = a;
        cout << "Person 带参构造函数被调用" << endl;
    }
};

class Student : public Person {
public:
    int studentID;

    // 派生类构造函数:初始化列表中调用基类构造
    Student(string n, int a, int id) : Person(n, a) {
        studentID = id;
        cout << "Student 带参构造函数被调用" << endl;
    }

    void show() {
        cout << "姓名:" << name << " 年龄:" << age << " 学号:" << studentID << endl;
    }
};

int main() {
    Student s("李四", 20, 2024002);
    s.show();
    return 0;
}

五、继承的实战案例:员工管理系统

需求设计一个简单的员工管理系统,包含普通员工 Employee 和经理 Manager 两类角色。Employee 包含姓名、工号、工资属性和工作方法;Manager 继承 Employee,并新增部门属性和管理方法。

5.1 需求分析
  1. 基类 Employee:属性(姓名、工号、工资),方法(工作 work())。
  2. 派生类 Manager:公有继承 Employee,新增属性(部门),新增方法(管理 manage())。
  3. 要求:通过构造函数初始化所有属性,保证数据完整性。
5.2 完整代码实现
#include <iostream>
#include <string>
using namespace std;

// 基类:普通员工
class Employee {
protected:
    string name;
    int empID;
    double salary;

public:
    // 带参构造函数
    Employee(string n, int id, double sal) {
        name = n;
        empID = id;
        salary = sal;
        cout << "Employee 构造函数被调用" << endl;
    }

    // 工作方法
    void work() {
        cout << "员工 " << name << "(工号:" << empID << ")正在工作,月薪:" << salary << endl;
    }

    ~Employee() {
        cout << "Employee 析构函数被调用" << endl;
    }
};

// 派生类:经理,公有继承普通员工
class Manager : public Employee {
private:
    // 新增属性:管理部门
    string department;

public:
    // 构造函数:初始化列表调用基类构造
    Manager(string n, int id, double sal, string dep) : Employee(n, id, sal) {
        department = dep;
        cout << "Manager 构造函数被调用" << endl;
    }

    // 新增方法:管理
    void manage() {
        cout << "经理 " << name << " 管理 " << department << " 部门" << endl;
    }

    // 重写基类的 work 方法(方法重写)
    void work() {
        cout << "经理 " << name << "(工号:" << empID << ")正在管理工作,月薪:" << salary << endl;
    }

    ~Manager() {
        cout << "Manager 析构函数被调用" << endl;
    }
};

int main() {
    // 创建普通员工对象
    Employee emp("王五", 1001, 5000.0);
    emp.work();
    cout << "-------------------------" << endl;

    // 创建经理对象
    Manager mgr("赵六", 9001, 15000.0, "技术部");
    mgr.work();       // 调用重写后的 work 方法
    mgr.manage();     // 调用新增的 manage 方法

    return 0;
}

运行结果:

Employee 构造函数被调用
员工 王五(工号:1001)正在工作,月薪:5000
-------------------------
Employee 构造函数被调用
Manager 构造函数被调用
经理 赵六(工号:9001)正在管理工作,月薪:15000
经理 赵六 管理 技术部 部门
Manager 析构函数被调用
Employee 析构函数被调用
Employee 析构函数被调用

六、继承的常见问题与解决方案

6.1 问题 1:派生类无法访问基类 private 成员

解决方案:

  1. 将基类需要被派生类访问的成员设置为 protected 权限。
  2. 在基类中提供 public 的 get/set 方法,让派生类间接访问 private 成员。
6.2 问题 2:基类无默认构造函数,派生类编译报错

解决方案: 在派生类的构造函数初始化列表中,显式调用基类的带参数构造函数。

6.3 问题 3:多重继承导致的二义性(钻石问题)

多重继承是指一个派生类同时继承多个基类,容易出现同名成员冲突的问题。

解决方案: 使用作用域解析符 :: 明确指定要访问的基类成员。

class A {
public:
    void func() {
        cout << "A 的 func 方法" << endl;
    }
};

class B {
public:
    void func() {
        cout << "B 的 func 方法" << endl;
    }
};

class C : public A, public B {};

int main() {
    C c;
    c.A::func(); // 明确调用 A 类的 func 方法
    c.B::func(); // 明确调用 B 类的 func 方法
    return 0;
}

七、总结

继承的核心是代码复用与功能扩展,派生类可以继承基类的属性和方法,并新增自己的专属内容。三种继承方式中,public 继承最常用,其权限规则是'不提升、只限制'。继承中的构造顺序是先基后派,析构顺序是先派后基,带参构造需要在初始化列表显式调用。多重继承容易引发二义性,可通过作用域解析符解决,实际开发中应谨慎使用多重继承。

目录

  1. C++ 继承详解:面向对象代码复用的核心机制
  2. 一、继承的核心概念
  3. 二、继承的基本语法与实现
  4. 2.1 语法格式
  5. 2.2 基础实现案例
  6. 三、三种继承方式的访问权限控制
  7. 3.1 权限对比表
  8. 3.2 不同继承方式的代码演示
  9. 3.2.1 public 继承演示
  10. 3.2.2 protected 继承演示
  11. 3.2.3 private 继承演示
  12. 四、继承中的构造与析构顺序
  13. 4.1 核心规则
  14. 4.2 代码演示:构造与析构顺序
  15. 4.3 带参数的构造函数继承
  16. 五、继承的实战案例:员工管理系统
  17. 5.1 需求分析
  18. 5.2 完整代码实现
  19. 六、继承的常见问题与解决方案
  20. 6.1 问题 1:派生类无法访问基类 private 成员
  21. 6.2 问题 2:基类无默认构造函数,派生类编译报错
  22. 6.3 问题 3:多重继承导致的二义性(钻石问题)
  23. 七、总结
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 基于 SpringBoot 和 PostGIS 的各省东西南北四至极点区县可视化
  • 资深工程师推荐:全球顶尖编程博客与思想领袖
  • Sudachi 开源模拟器跨平台使用指南
  • JSON 技术详解:核心优势、设计哲学与生态演进
  • FPGA 是什么:现场可编程门阵列的核心原理与应用
  • Java Map 常用方法与实现类深度详解
  • MySQL 互联网公司常用分库分表方案汇总
  • faster-whisper 快速安装与使用指南:AI 语音识别
  • 知网与维普 AIGC 检测对比:原理差异与选择建议
  • Windows Python 安装与配置完整教程
  • 深入理解 Git 主流工作流与团队协作实践
  • 阿里云 MoltBot 机器人钉钉 Stream 流式接入配置
  • 主流音视频传输协议(DP、HDMI、USB4 等)性能对比
  • Python 自动化:wxauto 安装失败解决方案与实战
  • C++高性能推理优化全解析:AIGC 场景下吞吐量提升策略
  • AI 与存储的结合:智能存储的实践与挑战
  • C++11 核心特性详解:列表初始化与右值引用
  • AI 数据标注平台的选型与实践:效率提升背后的技术逻辑
  • FPGA 高速通信:Aurora64B/66B IP 使用指南
  • 大模型技术框架与核心应用学习指南

相关免费在线工具

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online