首页 > 编程语言 >C++继承

C++继承

时间:2025-01-01 09:55:05浏览次数:3  
标签:继承 基类 C++ public Base 派生类 class

文章目录


前言

在 C++ 中,继承是面向对象编程(OOP)的一个重要特性,它允许一个类(称为子类或派生类)继承另一个类(称为父类或基类)的属性和方法。通过继承,可以实现代码重用,减少重复代码,并支持多态性。


一、访问修饰符

  • Public:基类的公有成员在派生类中仍然是公有的,保护成员在派生类中仍然是保护的。
  • Protected:基类的公有和保护成员在派生类中都成为保护成员。
  • Private:基类的公有和保护成员在派生类中都成为私有成员。

二、使用

1.单继承

代码如下(示例):

class Base {
public:
    void publicMethod() { /* ... */ }
protected:
    int protectedVar;
};
// :public Base 就是说以pubiic的方式继承
class Derived : public Base {
public:
    void anotherMethod() {
        // 可以访问 publicMethod 和 protectedVar
    }
};

2.多继承

代码如下(示例):

class Base1 {
public:
    void methodOfBase1() { /* ... */ }
};

class Base2 {
public:
    void methodOfBase2() { /* ... */ }
};
//这里就是多继承的写法
class Derived : public Base1, public Base2 {
public:
    void derivedMethod() {
        methodOfBase1();
        methodOfBase2();
    }
};

C++ 支持一个类从多个基类继承。

3.虚继承

代码如下(示例):

class Base {
public:
    virtual ~Base() {}
};
//增加一个virtual关键字
class Derived1 : virtual public Base {};
class Derived2 : virtual public Base {};

class MultiDerived : public Derived1, public Derived2 {
public:
    MultiDerived() {}
};

当存在多重继承且多个基类拥有共同的基类时,可能会导致二义性和重复继承的问题。虚拟继承用于解决这些问题。

4.纯虚函数

class Base {
public:
    virtual void pure_virtual_function() = 0; // 纯虚函数
};

class Derived : public Base {
public:
    void pure_virtual_function() override {
        // 提供具体的实现
    }
};

包含纯虚函数的类被称为抽象类,而不能创建抽象类的对象,只能创建其非抽象派生类的对象。

定义纯虚函数的主要目的是为派生类提供一个统一的接口,同时允许不同的派生类根据自己的特点来实现该接口。继承了抽象类的对象想要实例化,必须重写纯虚函数,这样可以确保所有派生类都必须实现这个函数,从而保证了一定程度上的代码一致性。

5.析构函数与继承

代码如下(示例):

class Base {
public:
    virtual ~Base() {}
};
//增加一个virtual关键字
class Derived1 : virtual public Base {};
class Derived2 : virtual public Base {};

class MultiDerived : public Derived1, public Derived2 {
public:
    MultiDerived() {}
};

在继承体系中,如果基类定义了析构函数,那么通常应该将其声明为虚函数(virtual),以确保当通过基类指针删除派生类对象时,派生类的析构函数也会被调用。

三.容易出现的问题

1.菱形继承问题

也称为死亡钻石,是面向对象编程中多继承带来的一个经典问题。这个问题得名于继承结构图的形状,该形状类似于菱形或钻石。

菱形继承
在这个例子中,D 类同时继承自 B 和 C,而 B 和 C 都继承自 A。如果 A 中有一个方法或属性,那么在 D 中访问这个成员时就可能出现二义性,因为 D 可以通过 B 或 C 继承得到两个版本的 A 的成员。这在某些语言中会导致编译错误,或者如果不处理好,可能会导致程序行为不符合预期。
可以通过使用虚继承(virtual inheritance)来解决菱形继承的问题。虚继承确保了即使一个类从多个路径继承同一个基类,它也只会拥有该基类的一个实例,从而避免了二义性和重复构造基类的问题。

2.二义性

当一个派生类从多个基类继承,并且这些基类有同名成员时,访问该成员会导致编译器无法确定应该使用哪个基类的成员,从而产生二义性。
解决方法包括显式地指定要使用的基类成员,例如 BaseClass::member,或者通过虚继承来确保只有一个基类副本。

3.内存布局复杂性

多继承和虚继承会增加对象的内存布局复杂度,可能引入额外的指针(如虚表指针),并导致对象大小增加。

4.代码可读性和维护性下降

随着继承层次的加深和复杂性的增加,代码变得更加难以理解和维护。过度依赖继承而非组合,可能会使设计变得脆弱。

5.紧耦合

继承建立了一种强耦合关系,基类的变化可能会影响所有派生类。为了降低这种风险,可以考虑使用接口或纯虚函数类来定义行为契约,而不是具体的实现。

6.使用推荐

为了避免这些问题,开发者应该遵循“组合优于继承”的原则(不知道组合的话可以了解一下),在适当的情况下优先选择对象组合而非继承。此外,使用单一责任原则(SRP)来限制每个类的责任范围,也可以帮助简化继承体系,提高代码的可维护性和灵活性。

四.优缺点

1.C++ 继承的优点

  • 代码重用:
    继承允许创建新的类(派生类),这些类可以继承现有类(基类)的属性和方法,从而减少了重复代码的数量,并提高了代码的可维护性。
  • 扩展性:
    派生类可以在不修改基类的情况下增加新的功能或覆盖已有功能。这有助于软件的演进和发展,同时保持了旧版本的兼容性。
  • 多态性:
    通过虚函数和接口,继承支持运行时多态性,使得程序能够在不知道具体类型的情况下调用对象的方法。这增加了灵活性,简化了复杂系统的设计。
  • 层次结构建模:
    继承可以帮助构建清晰的对象层次结构,模拟现实世界中的“is-a”关系,比如“狗是一种动物”,这种关系在某些应用领域(如图形界面、游戏开发等)特别有用。
  • 抽象与接口分离:
    使用纯虚函数或抽象类,可以让基类定义一个接口而不提供实现,迫使派生类去实现这些接口,有助于建立良好的设计模式。

2.C++ 继承的缺点

  • 紧耦合:
    继承创建了基类和派生类之间的紧密依赖关系,基类的变化可能会影响所有派生类,这可能会导致维护上的困难。
  • 脆弱的基类问题:
    基类的一个小改动可能导致所有派生类的行为发生变化,甚至破坏它们的功能。这被称为“脆弱基类问题”。
  • 二义性和菱形继承问题:
    在多重继承中,可能会出现二义性或菱形继承问题,这些问题需要额外的机制(如虚拟继承)来解决,但也会增加代码的复杂度。
  • 构造和析构顺序的问题:
    构造函数和析构函数的执行顺序是固定的,如果处理不当,可能会导致未初始化成员变量或其他问题。
  • 性能开销:
    虚函数调用引入了一定程度的间接性,可能会带来轻微的性能损失。此外,复杂的继承层次可能会增加对象的大小和内存布局的复杂性。
  • 设计复杂度:
    过度使用继承会导致类的设计变得复杂,难以理解和维护。尤其是在大型项目中,深且宽的继承树可能会使代码库难以管理。
  • 组合优于继承:
    在很多情况下,使用对象组合(Composition)而不是继承能够更好地解决问题,因为组合提供了更大的灵活性,降低了模块间的耦合度。

总结

继承是一个强大的工具,但它并非总是最优的选择。在C++编程中,应该谨慎地评估是否使用继承以及如何使用它。遵循“组合优于继承”的原则,在适当的情况下优先选择组合,可以使代码更加灵活、易于理解和维护。同时,利用继承的优势,如代码重用和多态性,可以有效地提高软件的质量和效率。

标签:继承,基类,C++,public,Base,派生类,class
From: https://blog.csdn.net/qq_62718148/article/details/144861801

相关文章

  • GESP2024年6月认证C++五级( 第三部分编程题(2))
    参考程序(线性筛法)#include<iostream>#include<vector>usingnamespacestd;constintMAXN=10000001;//最大数字范围//保存每个数的质因子数量vector<int>primeFactors(MAXN,0);voidlinearSieve(){//从2开始筛选for(inti=2;i<MAXN;......
  • 【C++】B2085 第 n 小的质数
    博客主页:[小ᶻ☡꙳ᵃⁱᵍᶜ꙳]本文专栏:C++文章目录......
  • 【C++】BC89 包含数字9的数
    博客主页:[小ᶻ☡꙳ᵃⁱᵍᶜ꙳]本文专栏:C++文章目录......
  • Godot引擎开发:GDScript脚本编写_类和继承
    类和继承在Godot引擎中,GDScript是一种类似于Python的脚本语言,专门用于游戏开发。类和继承是面向对象编程的核心概念,掌握这些概念对于编写高效、可维护的代码至关重要。本节将详细介绍如何在GDScript中使用类和继承,包括类的定义、属性和方法的使用,以及如何通过继承来扩......
  • Godot引擎开发:GDScript脚本编写_类和继承
    类和继承在Godot引擎中,GDScript是一种类似于Python的脚本语言,专门用于游戏开发。类和继承是面向对象编程的核心概念,掌握这些概念对于编写高效、可维护的代码至关重要。本节将详细介绍如何在GDScript中使用类和继承,包括类的定义、属性和方法的使用,以及如何通过继承来扩......
  • 关于C++游戏开发入门:如何从零开始实现一个完整的游戏项目!
      成长路上不孤单......
  • 【C++11】智能指针
    目录指针标准库unique_ptr对应类方法创建unique_ptr对象的两种方法unique_ptr的使用特性shared_ptr类方法循环引用造成内存泄漏weak_ptrweak_ptr的创建三个方法功能例子1例子2指针普通指针:指向内存区域的地址变量当普通指针指向动态分配的内存的时候,即使这个指......
  • C++ 游戏开发技术文档
    项目概述本技术文档将指导开发一个使用C++构建的简易2D游戏框架。该游戏是一个玩家控制角色收集随机生成的道具的小游戏,核心功能包括:游戏循环:支持帧率控制和逻辑更新。玩家控制:通过键盘控制角色上下左右移动。道具生成与收集:随机生成道具,玩家接触道具后得分。基本碰撞......
  • yolov5单目测距与相机标定流程和c++单目测距RKNN部署
    相机模型、相机标定及基于YOLOv5的单目测距实现1.前言注意此方法不需要预先知道物体尺寸,不需要参照物体!!!!在摄像头成像的过程中,物体反射的光线通过摄像头的凸透镜聚焦到成像器件上,形成一张二维图像。这一过程将三维世界中的物体转换为二维图像,导致深度信息丢失,因此单目摄......
  • LeetCode算法题 (比较含退格的字符串)Day9!!!C/C++
    https://leetcode.cn/problems/backspace-string-compare/description/一、题目描述给定 s 和 t 两个字符串,当它们分别被输入到空白的文本编辑器后,如果两者相等,返回 true 。# 代表退格字符。注意:如果对空文本输入退格字符,文本继续为空。二、相关知识点了解   ......