C++基础——继承(下)

一、继承与静态成员

基类定义了static 静态成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子

类,都只有一个 static 成员实例 。


class person
{
public:person(const char* name = "lisi"):_name(name){}
public:string _name;// 静态成员属性static int count;
};
class worker : public person
{
public:protected:string _job_number = "111";
};
// 静态成员属性需要在类外定义
int person::count = 0;void Test2(void)
{person pobj;worker wobj;pobj._name = "wangwu";cout << pobj._name << endl;cout << wobj._name << endl;cout << "wobj.count: " << wobj.count << endl;// 基类更改这个静态成员pobj.count = 5;cout << "wobj.count: " << wobj.count << endl;cout << "&pobj.count = " << &pobj.count << endl;cout << "&wobj.count = " << &wobj.count << endl;
}

静态成员属性需要在类外定义;

上面的_name,基类对象和派生类对象各自私有一份,而对于静态成员变量 count,派生类继承的 count 和基类里面的 count 是同一份。

即基类里面的静态成员,无论有多少个派生类,它们都共享同一个静态成员。

二、单继承

单继承:一个派生类只有一个直接基类,我们称这个继承关系为单继承。

class Person{};
class Worker : public Person{};
class Teacher : public Worker{};

三、多继承

多继承:一个派生类有两个或以上直接基类时称这个继承关系为多继承。

四、菱形继承

类似以上继承为菱形继承。

菱形继承会产生数据冗余和二义性的问题。在Assistant的对象中Person成员会有两份。

二义性无法明确知道访问的是哪一个,需要显示指定访问哪个父类的成员可以解决二义性问题,但是数据冗余问题无法解决。

那么该怎么解决呢?

虚拟继承可以解决菱形继承的二义性和数据冗余的问题。

五、虚拟继承

为解决菱形继承的二义性和数据冗余,我们采用菱形继承,我们看以下代码:

class A
{
public:int _a;
};
// class B : public A
class B : virtual public A
{
public:int _b;
};
// class C : public A
class C : virtual public A
{
public:int _c;
};
class D : public B, public C
{
public:int _d;
};
int main()
{D d;d.B::_a = 1;d.C::_a = 2;d._b = 3;d._c = 4;d._d = 5;return 0;
}

六、总结

1.很多人说C++语法复杂,其实多继承就是一个体现。有了多继承,就存在菱形继承,有了菱形继承就有菱形虚拟继承,底层实现就很复杂。所以一般不建议设计出多继承,一定不要设计出菱形继承。否则在复杂度及性能上都有问题。

2.多继承可以认为是C++的缺陷之一,很多后来的语言都没有多继承,如Java

3.继承和组合的区别?什么时候用继承?什么时候用组合?


继承和组合是面向对象编程中两种常见的代码重用机制,它们有不同的使用场景和特点。

继承:

  • 继承是一种“is-a”关系,它描述了两个类之间的一种层次结构,子类继承了父类的属性和方法,并且可以添加自己的新属性和方法。
  • 适合于在现有类的基础上进行扩展,通过重用现有类的代码来实现新类的功能。
  • 通常用于描述一种分类或分类的关系,子类是父类的特例,具有更具体的特征或行为。
  • 适用于需要实现代码的重用和扩展的情况。

组合:

  • 组合是一种“has-a”关系,它描述了两个类之间的一种包含关系,一个类包含另一个类的实例作为其成员变量。
  • 适合于描述一种包含关系,其中一个类包含另一个类的实例,并且通过这种组合来实现更复杂的功能。
  • 通常用于描述一种组合或拥有关系,其中一个类包含了另一个类的实例作为其一部分。
  • 适用于需要将不同的类组合在一起实现某个功能的情况,而不是通过继承来实现。

在未来代码设计中,遵循的设计原则是:低耦合,高内聚。

在选择继承还是组合时,可以考虑以下几点:

  • 代码重用性:如果需要重用现有类的代码并扩展其功能,则可以选择继承。如果只是需要利用现有类的功能而不需要扩展其功能,则可以选择组合。
  • 耦合性:继承会增加类之间的耦合性,子类与父类之间存在较强的依赖关系,而组合可以降低耦合性,类之间的关系更灵活。
  • 设计灵活性:组合比继承更灵活,因为可以随时更改组合关系,而不会影响类的结构。继承则更加静态,子类的结构受限于父类的定义。

4.如何定义一个无法被继承的类?

第一种方式C++98,将基类的构造私有化,派生类继承这个基类,在实例化对象时,需要调用基类的构造,但由于基类的构造已经私有化,故会编译报错。

class A
{
public://将基类的构造函数私有化
private:   A(int a = int()):_a(a){cout << "A()" << endl;};
protected:int _a;
};class B : public A
{
protected:int _b;
};

对于 C++11 的做法是:通过关键字 final,被final修饰的类无法被继承,编译器会强制检查。

// 用 final 修饰 A类, 此时A类无法被继承
class A final
{
public:A(int a = int()) :_a(a){cout << "A()" << endl;}
protected:int _a;
};class B : public A
{
protected:int _b;
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/704824.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

54.指针

目录 一.什么是指针&#xff1f; 二&#xff0e;定义一个指针变量 三&#xff0e;指针变量类型 四&#xff0e;取地址运算符& 五.取值运算符* 六.视频教程 一.什么是指针&#xff1f; 口语中的指针一般指指针变量&#xff0c;指针变量存放的是一个地址。普通变量存放…

TCP(1)

传输层的两大协议是TCP 和 UDP &#xff0c;他们在传输数据的时候起到了不可替代的作用。那么什么是TCP呢&#xff1f; 首先TCP是一个网络传输协议&#xff0c;这个协议保证了可靠的数据传输。TCP是面向字节流的&#xff0c;全双工的&#xff08;也就是通信双方互相发消息&…

shell脚本之sort,uniq,tr,cut,sphit,paste,ecal与正则表达式

sort命令 uniq命令 tr命令 cut命令 sphit命令 paste命令 ecal命令 正则表达式 sort命令 sort命令---以行为单位对文件内容进行排序&#xff0c;也可以根据不同的数据类型来排序 比较原则是从首字符向后&#xff0c;依次按ASCII码值进行比较&#xff0c;最后将他们按升序…

Redis 源码安装和入门介绍

Linux下的redis源码安装 redis介绍 Redis 是一个开源&#xff08;BSD许可&#xff09;的&#xff0c;内存中的数据结构存储系统&#xff0c;它可以用作数据库、缓存和消息中间件。它支持多种类型的数据结构&#xff0c;如 字符串&#xff08;strings&#xff09;&#xff0c;…

Leetcode - 周赛397

目录 一&#xff0c;3146. 两个字符串的排列差 二&#xff0c;3147. 从魔法师身上吸取的最大能量 三&#xff0c;3148. 矩阵中的最大得分 四&#xff0c;3149. 找出分数最低的排列 一&#xff0c;3146. 两个字符串的排列差 本题就是求同一个字符在两个字符串中的下标之差的…

Nacos+GateWay 搭建微服务架构

文章目录 1.当前项目架构分析1.请求多个模块的方式1.请求renren-fast模块开发环境生产环境 2.请求sunliving-commodity模块1.使用环境变量资源路径的方式2.开发环境 dev.env.js3.生产环境 prod.env.js 3.文件上传请求 sunliving-service模块1.请求后端接口&#xff08;开发环境…

基于网络爬虫技术的网络新闻分析(二)

目录 2 系统需求分析 2.1 系统需求概述 2.2 系统需求分析 2.2.1 系统功能要求 2.2.2 系统IPO图 2.2 系统非功能性需求分析 3 系统概要设计 3.1 设计约束 3.1.1 需求约束 3.1.2 设计策略 3.1.3 技术实现 3.3 模块结构 3.3.1 模块结构图 3.3.2 系统层次图 3.3.3…

低空经济:无人机竞赛详解

无人机竞赛市场近年来呈现出蓬勃发展的态势&#xff0c;其市场价值不仅体现在竞赛本身&#xff0c;还体现在推动无人机技术创新、拓展应用场景以及促进产业链发展等多个方面。 一、比赛项目介绍 无人机竞赛通常分为多个项目&#xff0c;包括竞速赛、技巧赛、航拍赛等。每个项目…

ADS使用记录之使用RFPro进行版图联合仿真-加入集总元器件

ADS使用记录之使用RFPro进行版图联合仿真-加入集总元器件 ADS使用记录之使用RFPro进行版图联合仿真中已经简单介绍了使用RFPro对版图就行仿真的方法。但是&#xff0c;如果版图中含有一些非微带的结构&#xff0c;比如说电感、电容、晶体管呢&#xff0c;在此举例解释一下。 …

Java--初识类和对象

前言 本篇讲解Java类和对象的入门版本。 学习目的&#xff1a; 1.理解什么是类和对象。 2.引入面向对象程序设计的概念 3.学会如何定义类和创建对象。 4.理解this引用。 5.了解构造方法的概念并学会使用 考虑到篇幅过长问题&#xff0c;作者决定分多次发布。 面向对象的引入 J…

英飞凌SiC模块为小米电动车提供动力

至2027年之际&#xff0c;SiC功率模块与裸片产品将荣耀登场&#xff0c;助力小米电动汽车新品SU7璀璨问世。英飞凌&#xff0c;这家业界翘楚&#xff0c;将倾其所能&#xff0c;为小米SU7 Max提供两颗HybridPACK Drive G2 CoolSiC 1200 V模块&#xff0c;如同给电动汽车的心脏注…

Linux进程控制——Linux进程程序替换

前言&#xff1a;Linux进程控制包含了进程终止&#xff0c;进程等待&#xff0c;进程程序替换。走到现在我们也只剩下进程程序替换没介绍了&#xff0c;那么让我们来看看进程程序替换到底是什么&#xff01; 本篇主要内容&#xff1a; 替换原理 替换函数 实现简易shell 我们所创…