C++ 继承与派生

一、继承与派生的核心概念

继承是 C++ 实现代码复用多态的基础:

  • 基类(父类):被继承的类,定义了通用的属性和方法。
  • 派生类(子类):从基类继承而来的类,可复用基类的成员,也可扩展新的成员或重写基类方法。你可以把继承理解为 "特殊化"------ 派生类是基类的一种特殊形式(例如:学生是人的特殊形式)。

二、继承的基本语法

1. 定义派生类

语法格式:

cpp

运行

复制代码
class 派生类名 : 继承方式 基类名 {
    // 派生类新增的成员(属性/方法)
};

继承方式有三种(核心是控制基类成员在派生类中的访问权限):

继承方式 基类 public 成员 基类 protected 成员 基类 private 成员
public public protected 不可访问
protected protected protected 不可访问
private private private 不可访问
👉 最常用的是 public 继承,也是符合 "is-a" 逻辑的继承方式。
2. 基础示例(public 继承)

cpp

运行

复制代码
#include <iostream>
#include <string>
using namespace std;

// 基类:人类
class Person {
public:
    // 构造函数
    Person(string n, int a) : name(n), age(a) {}
    
    // 公有方法
    void ShowInfo() {
        cout << "姓名:" << name << ",年龄:" << age << endl;
    }
    
    // 可被派生类重写的方法
    void SayHello() {
        cout << "我是一个普通人" << endl;
    }

protected:
    // 保护成员:派生类可访问,外部不可访问
    string name;
private:
    // 私有成员:仅基类自身可访问
    int age;
};

// 派生类:学生(public继承Person)
class Student : public Person {
public:
    // 派生类构造函数:必须先调用基类构造函数初始化基类成员
    Student(string n, int a, int id) : Person(n, a), studentId(id) {}
    
    // 新增方法
    void ShowStudentInfo() {
        // 可访问基类的protected成员name
        cout << "姓名:" << name << ",学号:" << studentId << endl;
        // age是private,此处访问会报错:error: 'int Person::age' is private
        // cout << age << endl; 
    }
    
    // 重写基类方法(覆盖)
    void SayHello() {
        cout << "我是学生,姓名:" << name << endl;
    }

private:
    // 新增私有成员
    int studentId;
};

int main() {
    // 创建派生类对象
    Student stu("张三", 18, 2025001);
    
    // 调用继承自基类的方法
    stu.ShowInfo(); // 输出:姓名:张三,年龄:18
    
    // 调用派生类新增方法
    stu.ShowStudentInfo(); // 输出:姓名:张三,学号:2025001
    
    // 调用重写后的方法
    stu.SayHello(); // 输出:我是学生,姓名:张三
    
    return 0;
}

三、继承中的核心规则

1. 构造函数与析构函数
  • 构造顺序 :先调用基类构造函数 → 再调用派生类构造函数。

  • 析构顺序 :先调用派生类析构函数 → 再调用基类析构函数。

  • 派生类构造函数必须显式 / 隐式初始化基类: cpp

    运行

    复制代码
    // 显式调用基类构造函数(推荐)
    Student(string n, int a, int id) : Person(n, a), studentId(id) {}
    
    // 隐式调用:如果基类有默认构造函数(无参),可省略
    class Person {
    public:
        Person() {} // 默认构造函数
    };
    class Student : public Person {
    public:
        Student(int id) : studentId(id) {} // 隐式调用Person()
    };
2. 方法重写(覆盖)
  • 派生类可以重写基类的非 private 方法,但需注意:
    • 默认情况下,重写不会形成多态(需结合virtual关键字,见下文)。
    • 重写的方法签名(返回值、参数、const)必须与基类完全一致。
3. 多态(虚函数)

如果希望通过基类指针 / 引用调用派生类的重写方法(动态多态),需将基类方法声明为virtual

cpp

运行

复制代码
// 基类:将SayHello声明为虚函数
class Person {
public:
    virtual void SayHello() { // 虚函数
        cout << "我是一个普通人" << endl;
    }
};

// 派生类:重写虚函数
class Student : public Person {
public:
    void SayHello() override { // override关键字显式声明重写(C++11+)
        cout << "我是学生" << endl;
    }
};

int main() {
    Person* p = new Student(); // 基类指针指向派生类对象
    p->SayHello(); // 输出:我是学生(动态多态)
    delete p;
    return 0;
}
4. 继承的特殊形式
  • 单继承:一个派生类只继承一个基类(上文示例),最常用。

  • 多继承 :一个派生类继承多个基类(C++ 特有,需谨慎使用):

    cpp

    运行

    复制代码
    // 基类1
    class A { public: void FuncA() { cout << "A" << endl; } };
    // 基类2
    class B { public: void FuncB() { cout << "B" << endl; } };
    // 多继承
    class C : public A, public B {
    public:
        void FuncC() { cout << "C" << endl; }
    };
    
    int main() {
        C c;
        c.FuncA(); // 输出A
        c.FuncB(); // 输出B
        c.FuncC(); // 输出C
        return 0;
    }

    ❗ 多继承易引发 "菱形继承" 问题(两个基类继承同一个基类,派生类继承这两个基类),需用virtual继承解决。

四、继承的典型应用场景

  1. 代码复用:将多个类的通用属性 / 方法抽离为基类,派生类直接继承,避免重复代码。

  2. 多态设计 :通过基类指针 / 引用统一管理不同派生类对象,例如:

    cpp

    运行

    复制代码
    // 基类:图形
    class Shape {
    public:
        virtual double GetArea() = 0; // 纯虚函数(抽象方法)
    };
    // 派生类:圆形
    class Circle : public Shape {
    private:
        double r;
    public:
        Circle(double r) : r(r) {}
        double GetArea() override { return 3.14 * r * r; }
    };
    // 派生类:矩形
    class Rectangle : public Shape {
    private:
        double w, h;
    public:
        Rectangle(double w, double h) : w(w), h(h) {}
        double GetArea() override { return w * h; }
    };
    
    // 统一计算面积
    void PrintArea(Shape* s) {
        cout << "面积:" << s->GetArea() << endl;
    }
    
    int main() {
        PrintArea(new Circle(5)); // 输出:面积:78.5
        PrintArea(new Rectangle(4, 5)); // 输出:面积:20
        return 0;
    }
  3. 分层设计:例如框架中的基类定义核心接口,派生类实现具体业务逻辑。

总结

  1. 继承核心 :派生类通过public/protected/private继承基类,复用基类成员并扩展自身功能,构造先基后派、析构先派后基。
  2. 访问控制:public 继承是最常用的方式,基类 public/protected 成员在派生类中保持原有访问权限,private 成员不可访问。
  3. 多态关键 :基类方法声明为virtual,派生类用override重写,可通过基类指针 / 引用实现动态多态,这是继承的核心价值之一。
相关推荐
小大宇17 分钟前
python sqlalchemy 案例
开发语言·python
小保CPP21 分钟前
OpenCV C++基于模糊数学的图像滤波
c++·人工智能·opencv·计算机视觉
名字还没想好☜44 分钟前
Go 结构体内存对齐:调整字段顺序,同样的字段省下 40% 内存
开发语言·后端·golang·go·内存对齐
玛丽莲茼蒿1 小时前
很难出错的Spring5(十)—— IOC进阶
java·开发语言·jvm
Ulyanov1 小时前
雷达导引头仿真中的坐标系——从惯性系到量测角
开发语言·python·算法·系统仿真·雷达信号处理·雷达导引头
上海安当技术1 小时前
车间电脑指纹登录怎么做?从 FIDO2 公钥体系到统一身份认证的技术拆解
开发语言·电脑·php
前鼻音太阳熊1 小时前
【MES系统】- 工业HMI状态机可视化实践:从手写SVG到Cytoscape.js的技术选型与踩坑
开发语言·javascript·ecmascript
明日清晨1 小时前
VS2022禁用 NRVO/返回值优化(不调用拷贝构造函数处理方式)
c++
阿米亚波2 小时前
【C++ STL】std::array
java·开发语言·c++
choumin2 小时前
结构型模式——组合模式
c++·设计模式·组合模式·结构型模式