当前位置: 首页 > news >正文

C++第十三篇:继承

目录

一、继承的格式

二、继承的实现

三、菱形继承

四、虚继承

在 C++ 中,继承是面向对象编程的三大核心特性之一(另外两个是封装和多态),它允许一个类(子类 / 派生类)继承另一个类(父类 / 基类)的属性和方法,从而实现代码复用和层次化设计。

什么时候使用继承呢?

is a的关系。(就是说子类时父类的一个特殊的类型,就好比”圆形“和“图形”的关系,圆形是归属图形的一种,圆形有图形的特征,需要继承自图形。在好比打王者荣耀时的“韩信”和“英雄”的关系,韩信是一个英雄,它有英雄的基本特征,如血条,蓝条等等。)

存在层次关系和实现多态的场景会使用继承。

在没有必要使用继承时,尽量去减少继承的使用,否则可能会导致类关系复杂,难以梳理。

一、继承的格式

class 派生类名:继承方式 基类名1,继承方式 基类名2,....
{
派生类成员;
};

这里继承的有不同方式,分别有public、protected、private继承,继承方式的作用是限制基类成员在派生类中的访问级别。下面是不同继承下的访问权限:

这张图的意思就是,基类的private成员,不论派生类使用哪种继承,都是不可访问的;基类的protected成员,在protected和public继承下是属于protected的,在private继承下属于private;基类的public的成员在,在三种不用的继承下,分别属于不同的级别。

这里顺便在说一下三种级别的区别:

  • public:类内、派生类内、类外(通过对象)都能访问。
  • protected:仅类内和派生类内可访问,类外不可。
  • private:仅类内可访问,派生类和类外都不可。

二、继承的实现

举例:

#include <iostream>
#include <string>
using namespace std;// 基类:英雄类
class Hero {
protected:string name;       // 英雄名称int health;        // 生命值int attack;        // 攻击伤害float moveSpeed;   // 移动速度
public:// 构造函数:初始化英雄基本属性Hero(string n, int h, int a, float ms) : name(n), health(h), attack(a), moveSpeed(ms) {cout << "英雄 [" << name << "] 已创建!" << endl;}// 析构函数~Hero() {cout << "英雄 [" << name << "] 已销毁!" << endl;}
};// 派生类:韩信(继承自英雄类)
class HanXin : public Hero {
private:int skillDamage;   // 技能额外伤害
public:// 构造函数HanXin() : Hero("韩信", 3800, 180, 4.5), skillDamage(350) {cout << "韩信:\"到达胜利之前,无法回头!\"" << endl;}// 析构函数~HanXin()  {cout << "韩信:\"我的心,可不冷...\"" << endl;}
};int main() {HanXin hanxin;          // 创建韩信对象return 0;
}

结果如下:

这就是一个继承的实例,在运行的结果我们可以看到构造函数的调用顺序,先构造基类,然后是派生类,释放时先调用派生类的析构,再调用基类的析构函数。

这就是一个继承,上面介绍的时候就说了,继承也是为了多态的实现。那下来就来来看看什么事多态。

三、菱形继承

菱形继承是多继承中一种特殊且容易引发问题的场景,因类继承关系图呈菱形而得名。

菱形继承的关系。

  • B 和 C 都继承自 A
  • D 同时继承 B 和 C
  • 此时 D 会间接包含两份 A 的成员(一份来自 B,一份来自 C),可能导致问题。

代码示例:

#include <iostream>
using namespace std;// 基类 A
class A {
public:int a;A() : a(10) { cout << "A 构造" << endl; }
};// 基类 B(继承 A)
class B : public A {
public:B() { cout << "B 构造" << endl; }
};// 基类 C(继承 A)
class C : public A {
public:C() { cout << "C 构造" << endl; }
};// 派生类 D(同时继承 B 和 C)
class D : public B, public C {
public:D() { cout << "D 构造" << endl; }
};int main() {D d;// cout << d.a << endl;   错误:二义性// 必须显式指定来源cout << "B::a = " << d.B::a << endl; // 来自 B 继承的 Acout << "C::a = " << d.C::a << endl; // 来自 C 继承的 Areturn 0;
}

结果如下:

从结果上发现,这个A被构造了两次,同时在访问数据上,必须要指明数据的来源。这就是菱形继承带来的问题,数据冗余和二义性。

怎么解决呢?这里又有了虚继承。

四、虚继承

虚继承是为了解决菱形继承所带来的数据冗余和二义性。直接看代码:

#include <iostream>
using namespace std;class A {
public:int a;A() : a(10) { cout << "A 构造" << endl; }
};// 虚继承 A
class B : virtual public A {
public:B() { cout << "B 构造" << endl; }
};// 虚继承 A
class C : virtual public A {
public:C() { cout << "C 构造" << endl; }
};class D : public B, public C {
public:D() { cout << "D 构造" << endl; }
};int main() {D d;// 正常访问:仅一份 A::acout << "d.a = " << d.a << endl; // 10return 0;
}

结果如下:

可以看到,A类现在只被创建了一次,同时数据也可以直接访问了。

这个虚继承的思想很好理解。实际就是虚基类(A)的实例只被创建一次,并被所有间接继承它的中间基类(BC)和派生类(D共享。有个虚基类表和虚基类指针的作用是记录这个唯一实例的地址,确保BCD都能通过统一的路径访问A的成员,从而避免数据冗余和二义性。

http://www.dtcms.com/a/512039.html

相关文章:

  • GD32F407VE天空星开发板SPI配置详解
  • 公司网站建设优帮云企业网站建设需注意什么
  • 垂直原理:宇宙的沉默法则与万物运动的终极源头
  • 如何在没有 iCloud 的情况下备份 iPhone
  • 江苏专业网站建设ps软件手机版
  • 番禺制作网站平台女孩学电子商务专业好就业吗
  • 自动点焊机——为电动自行车打造稳定动力
  • 栈与队列:数据结构中的双雄对决
  • Jenkins 安装,自动化全方位详解文档
  • 第八节_PySide6基本窗口控件_按钮类控件(QAbstractButton)
  • iBizModel 工作流(PSWORKFLOW)模型体系详解
  • 装修公司网站源码网站怎样做免费优化有效果
  • 20.1 ChatPPT v3.0颠覆发布:多模态图像识别+AI生成,办公效率提升500%的核心拆解
  • 【PyTorch】单目标检测部署
  • 3D超点(3D Superpoint)概念解释与代码实现
  • TPAMI 2025 | 从分离到融合:新一代3D场景技术实现双重能力提升!
  • malloc/free 内存问题
  • 国企集团门户网站建设方案有什么做数学题的网站
  • CredentialProvider多用户登录实现
  • ‘/‘ 和 ‘./‘在Vite中的区别
  • 技术指南:如何高效地将SOLIDEDGE模型转换为3DXML格式
  • C#上位机工程师技能清单文档
  • 考研408《操作系统》复习笔记,第二章《2.4 同步互斥》
  • 复现AB3DMOT 3D目标跟踪
  • 两种方法解决SQL连续登录问题
  • 一种简易的python c++协同定位和dump数据的方式
  • 蒙帕视角丨图像高效端到端目标检测
  • 孟村网站建设虚拟资源站码支付wordpress
  • xv6 源码精读(二)开启MMU、一致性映射页表
  • 珠海网站建设尚古道策略长沙口碑好网站建设公司