C++的继承

C++的继承

继承的基础语法

C++继承是一个类(派生类)继承了另一个类(基类)的所有成员(成员变量和成员函数),除了构造函数、析构函数以及被声明为私有的成员之外。

继承的定义格式:

继承方式:

【注意点】:

  1. 同名隐藏:如果派生类定义了一个与基类同名的成员(包括成员变量或成员函数),那么派生类的成员将会隐藏基类的成员。可以使用 作用域解析运算符:: 来明确引用基类的成员。

(尽量避免同名,同名函数不会构成重载,重载要求在相同的作用域中,而基类和派生类都有独立的作用域)

  1. 友元和静态成员:友元关系不被继承。静态成员属于整个类,而不是某个特定的对象实例,因此无论是基类还是派生类共享相同的静态成员。

基类和派生类对象的赋值转换

  • 派生类对象可以赋值给 基类的对象/基类的指针/基类的引用。
    (形象说法 "切片",寓意把派生类中父类那部分切来赋值过去)
cpp 复制代码
//赋值兼容 (切片)
Student s;

Person p = s;
Person* pp = &s;
Person& rp = s;

//不会产生中间临时变量,没有发生类型转换
  • 基类对象不能直接赋值给派生类对象。
  • 基类的指针或引用可以强制类型转换赋值给派生类的指针或引用。
    (必须是基类的指针指向派生类对象才是安全的)

派生类的默认成员函数

  1. 派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认构造函数,则必须在派生类构造函数的初始化列表阶段显示调用。

  2. 派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化,派生类的operator= 要调用基类的operator= 完成基类的复制,没有默认的需显式调用。


  3. 派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员,以保证派生类对象先清理派生类成员,再清理基类成员的顺序。

    (因为析构函数会被统一重写为destructor(),所以基类的析构函数应该声明为virtual)

  4. 派生类对象初始化先调用基类构造,再调派生类构造。

因为子类可能依赖于父类的成员变量或方法,这些都需要在子类构造之前被正确初始化,所有先构造父类;而析构先释放子类特有的资源,再释放父类资源,是为了避免访问已释放的资源。

菱形继承和菱形虚拟继承

菱形继承:菱形继承是多继承的一种特殊情况。

虚拟继承的写法:

菱形中间有成员被重复继承的两个类,继承方式前加上 virtual 。

这样就解决了数据冗余和访问二义性的问题。为了实现这一点,编译器会在 Student 和 Teacher 类的对象布局中各添加一个指向共享的 Person 实例的指针,这个指针通常被称为虚基表指针(vbptr),它指向同一个虚基表(vbtable),该表记录了如何从各自独有的对象所处于位置到共享对象的偏移量。

IDE里的实例:

虚拟继承总结:知道这个处理办法就行,写代码时尽量避免菱形继承。

相关推荐
Clarence Liu12 小时前
用 Go 从 100 亿个数中找到最小的 100 个数 —— 实战与原理
开发语言·后端·golang
闻缺陷则喜何志丹12 小时前
【计算几何】平面凸包
c++·数学·扫描线·凸包·单调性·上凸包·下凸包
xiaowu08012 小时前
IEnumerable、IEnumerator接口与yield return关键字的相关知识
java·开发语言·算法
csbysj202012 小时前
Perl 目录操作指南
开发语言
-To be number.wan12 小时前
C++ 运算符重载入门:让“+”也能为自定义类型服务!
开发语言·c++
未来之窗软件服务12 小时前
幽冥大陆(七十九)Python 水果识别训练视频识别 —东方仙盟练气期
开发语言·人工智能·python·水果识别·仙盟创梦ide·东方仙盟
王家视频教程图书馆12 小时前
android java 开发网路请求库那个好用请列一个排行榜
android·java·开发语言
汉克老师13 小时前
GESP2025年12月认证C++一级真题与解析(编程题1 (小杨的爱心快递))
c++·数据类型·选择结构·格式输出
小宇的天下13 小时前
Calibre Introduction to Calibre 3DSTACK(1)
开发语言
Vincent_Vang13 小时前
多态 、抽象类、抽象类和具体类的区别、抽象方法和具体方法的区别 以及 重载和重写的相同和不同之处
java·开发语言·前端·ide