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

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

💡 学习目标 :掌握继承的基本语法与核心特性,理解不同继承方式的访问权限控制,能够通过继承实现代码复用与扩展。

💡 学习重点:继承的语法格式、三种继承方式的区别、基类与派生类的关系、继承中的构造与析构顺序。

一、继承的概念与核心价值

结论 :继承是 C++ 面向对象三大特性之一,允许一个类派生类 继承另一个类基类的属性和行为,实现代码复用,同时支持派生类在基类基础上扩展新功能。

继承的核心价值体现在两个方面:

  1. 代码复用:避免重复编写相同的成员变量和成员函数,降低代码冗余度
  2. 功能扩展:派生类可以在基类的基础上新增属性和方法,满足更复杂的业务需求

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

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

2.1 继承的语法格式

cpp 复制代码
class 派生类名 : 继承方式 基类名 {
    // 派生类的成员
};
  • 继承方式 :决定基类成员在派生类中的访问权限,包括 publicprotectedprivate 三种
  • 基类名:被继承的类,也叫父类或超类
  • 派生类名:继承基类的类,也叫子类或衍生类

2.2 继承的基础实现案例

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

cpp 复制代码
#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;
    // 访问从基类继承的属性
    s.name = "张三";
    s.age = 18;
    // 访问派生类自身的属性
    s.studentID = 2024001;

    // 调用从基类继承的方法
    s.eat();
    s.sleep();
    // 调用派生类自身的方法
    s.study();

    return 0;
}

2.3 运行结果

复制代码
张三 正在吃饭
张三 正在睡觉
张三 正在学习,学号:2024001

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

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

3.1 三种继承方式的权限对比表

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

⚠️ 核心注意点

  1. 基类的 private 成员在派生类中始终不可直接访问 ,只能通过基类的 publicprotected 方法间接访问
  2. 继承方式的限制作用是单向的,派生类无法突破基类的权限限制
  3. 实际开发中,public 继承是最常用的方式,protected 和 private 继承仅在特定场景使用

3.2 不同继承方式的代码演示

3.2.1 public 继承演示
cpp 复制代码
#include <iostream>
#include <string>
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 继承演示
cpp 复制代码
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 继承演示
cpp 复制代码
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 代码演示:构造与析构顺序

cpp 复制代码
#include <iostream>
#include <string>
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;
    // 函数结束时对象销毁,自动调用析构函数
    return 0;
}

4.3 运行结果

复制代码
Person 基类构造函数被调用
Student 派生类构造函数被调用
Student 派生类析构函数被调用
Person 基类析构函数被调用

4.4 带参数的构造函数继承

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

cpp 复制代码
#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 完整代码实现

cpp 复制代码
#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;
}

5.3 运行结果

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

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

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

解决方案

  1. 将基类需要被派生类访问的成员设置为 protected 权限
  2. 在基类中提供 publicget/set 方法,让派生类间接访问 private 成员

6.2 问题2:基类无默认构造函数,派生类编译报错

解决方案

在派生类的构造函数初始化列表中,显式调用基类的带参数构造函数

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

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

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

cpp 复制代码
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 继承最常用,其权限规则是"不提升、只限制"。

✅ 继承中的构造顺序是先基后派,析构顺序是先派后基,带参构造需要在初始化列表显式调用。

✅ 多重继承容易引发二义性,可通过作用域解析符解决,实际开发中应谨慎使用多重继承。

相关推荐
纤纡.2 小时前
Python 实战:基于朴素贝叶斯的苏宁易购评价情感分析
开发语言·python·机器学习
西装没钱买2 小时前
C语言组播的使用
c语言·开发语言·udp·组播·组播绑定网卡
胖祥2 小时前
onnx之NodeComputeInfo
开发语言·c++·算法
MoonBit月兔2 小时前
报名仅剩 3 天|MoonBit 软件合成挑战赛已有数十个项目参赛!
开发语言·人工智能·编程·moonbit
sinat_255487812 小时前
为 System.out 编写我们自己的包装类
java·开发语言·算法
蓝天星空2 小时前
跨平台开发语言对比
开发语言·c#·.net
gihigo19982 小时前
距离角度解耦法的MIMO-OFDM雷达波束形成及优化MATLAB实现
开发语言·算法·matlab
愚者游世2 小时前
Qt 基础认知
c++·学习·程序人生·职场和发展·visual studio
独自破碎E2 小时前
【面试真题拆解】Java锁机制:synchronized、ReentrantLock、锁升级、可重入锁
java·开发语言·面试