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

C++ 继承实战:从语法细到员工管理系统

梳理C++继承的核心机制:三种继承方式的访问控制、构造析构顺序、带参构造的处理,以及如何用继承搭建一个简单的员工管理系统,同时指出常见陷阱与多重继承的二义性问题。

不知所云发布于 2026/6/16更新于 2026/8/2316 浏览
C++ 继承实战:从语法细到员工管理系统

在 C++ 里写面向对象,继承是绕不开的话题。说白了就是一个类可以把另一个类的属性和方法拿过来用,省得重复写。

继承关系示意图

继承主要干两件事:代码复用和功能扩展。拿现实来说,学生和老师都属于'人',都有姓名、年龄,也都会吃饭睡觉。先定一个 Person 基类,再让 Student 和 Teacher 去继承它,各自的专属属性(比如学号、工号)就能分开加了。

基本语法

语法很直白:

class 派生类名 : 继承方式 基类名 {
    // 派生类的成员
};
  • 继承方式 管着基类成员在派生类里的访问权限,有 public、protected、private 三种。
  • 基类名 就是被继承的那个,也叫父类。
  • 派生类名 就是子类。

来个最基本的例子——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 

三种继承方式:访问权限到底怎么变

继承方式影响基类成员在派生类里的可见性,但有一条基本规则:继承方式只会限制或保持原有权限,不会提升。具体看这张表:

| 基类成员权限 | public 继承 | protected 继承 | private 继承 | | --- | --- | --- | | public | public | protected | private | | protected | protected | protected | private | | private | 不可访问 | 不可访问 | 不可访问 |

几点实用提醒:

  1. 基类的 private 成员,派生类永远不能直接碰,只能靠基类的 public/protected 方法间接访问。
  2. 继承方式的限制是单向的,派生类没办法突破基类设的权限。
  3. 绝大多数场景下,public 继承就够了,protected 和 private 继承只在极少数设计里出现。

下面用代码演示三种继承的效果。

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;
}
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;
}
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;
}

构造与析构的固定顺序

创建派生类对象时,构造和析构的调用顺序是固定的:

  • 构造:先基类,再派生类。
  • 析构:先派生类,再基类。

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

下面这个例子会清楚打印出来:

#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 基类析构函数被调用

如果基类只有带参数的构造函数怎么办?派生类必须在初始化列表里显式调用基类构造,不然编译报错。

#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:姓名、工号、工资,还有 work()。
  • 派生类 Manager:公有继承自 Employee,新增 department,改写 work(),再加 manage()。
  • 所有属性通过构造函数初始化,保证数据完整。

完整代码:

#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 析构函数被调用

常见坑与解决思路

派生类访问不到基类的 private 成员

两种办法:

  1. 把基类里要被派生类访问的成员改成 protected。
  2. 在基类提供 public 的 get/set 接口。

基类没有默认构造函数,派生类编译报错

在派生类构造的初始化列表里显式调用基类的带参构造函数就行,前面已经演示过。

多重继承的二义性(钻石问题)

一个派生类同时继承多个基类,如果两个基类有同名成员,直接调用就会冲突。

解决:用作用域解析符 :: 明确指定用哪个基类的版本。

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;
}

继承解决的就是代码复用和扩展的问题,但用起来得留心权限控制、构造析构顺序这些细节。多重继承更是容易出坑,非必要不推荐。

目录

  1. 基本语法
  2. 三种继承方式:访问权限到底怎么变
  3. public 继承
  4. protected 继承
  5. private 继承
  6. 构造与析构的固定顺序
  7. 实战:一个简单的员工管理系统
  8. 常见坑与解决思路
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

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

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

更多推荐文章

查看全部
  • C++11 手写 Promise 实现及与 std::promise 对比
  • 没有项目经验,如何快速转行 AIGC 产品经理?
  • C++ 技术面试常见问题解析(三)
  • C++ 滑动窗口算法进阶解析与实战
  • 基于 OpenClaw 与飞书搭建多 Agent AI 助理团队
  • AI Coding 核心概念、工作流与上下文管理策略
  • Jimeng AI Studio 零代码 AI 绘画入门教程
  • Python 开源 AI 模型引入与测试全流程实战
  • C++ string 类基础用法与经典算法题解析
  • 哈希算法原理与实战:从 SHA-0 到应用场景详解
  • 积木报表快速入门与数据可视化实战
  • AIGC 中的变分自编码器(VAE)原理与 PyTorch 实现
  • OpenClaw Mac 本地化部署与飞书机器人接入指南
  • Go Map 底层原理详解
  • Tomcat 服务器部署与 Nginx 整合配置指南
  • Linux 进程信号处理机制与操作系统运行原理解析
  • 基于 Claude MCP 协议的智能体落地示例
  • Llama 3 AI 大模型技术总结与使用指南
  • 前端图像生成性能优化:5 个提升 DOM-to-image 效率的策略
  • Redis List 在现代 C++ 中的 redis-plus-plus 实践

相关免费在线工具

  • 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