C++中的继承方式与菱形继承解析

 更新时间:2023年08月08日 11:35:23   作者:烟华  
这篇文章主要介绍了C++中的继承方式与菱形继承解析,继承是类和类之间的关系,是代码复用的重要手段,允许在保持原有类结构的基础上进行扩展,创建的新类与原有的类类似,只是多了几个成员变量和成员函数,需要的朋友可以参考下

一.什么是继承?

继承是类和类之间的关系,是代码复用的重要手段,允许在保持原有类结构的基础上进行扩展,创建的新类与原有的类类似,只是多了几个成员变量和成员函数。

二.继承的方式

class 派生类名 :继承方式 基类名 {};

继承的方式有以下三种:

在这里插入图片描述

需要注意的是:

1.若不表明是以何种方式继承,使用关键字class时默认是私有继承,使用struct关键字时默认公有继承

2.上面的不可访问是指派生类对象不管是在类里还是类外都不能不访问

三.基类和派生类对象赋值转换

  1. 在public继承的情况下,派生类对象可以赋值给基类对象或基类指针或基类的引用,因为这里它是把一个派生类的对象看成是一个基类的对象,把派生类多的那一部分进行切片操作。 因此当一个基类的指针指向一个派生类的对象时,该指针只能访问基类定义的函数。(多态与此相反。如果基类的此函数声明为virtual类型,那么基类指针指向子类对象,该指针在调用该函数时会调用子类的函数)
  2. 当父类的对象赋值给派生类的指针时,这是十分危险的,虽然也能通过强制类型转换来进行赋值,但有可能出现越界的问题。

四.派生类的默认成员函数

构造函数

(1)派生类的构造函数需要调用基类的构造函数来初始化基类的那一部分成员。

(2)如果基类没有默认的构造函数而是自己写的构造函数,则必须在派生类的构造函数初始化列表阶段显 示调用,如果基类用的是默认构造函数,编译器会自动调用。

拷贝构造

(1)派生类的拷贝构造函数需要调用基类的拷贝构造函数完成基类的拷贝初始化

(2)默认拷贝构造会自动调用父类的拷贝构造。显式定义子类的拷贝构造,编译器默认调用的父类构造函数

赋值运算符重载

(1)派生类的operator=需要调用基类的operator=完成基类的赋值

(2)默认生成的赋值运算符会自动调用父类的赋值运算符显式定义子类的赋值运算符, 编译器不会自动调用父类的赋值运算符

析构函数

(1)派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。派生类对象析构清理先调用派生类的析构再调用基类的析构

(2)父类与子类析构构成同名隐藏:编译器底层修改的析构函数的名字,为了支持多态

(3)父类析构在任何情况下编译器都会自动调用,不需要显式调用

五.同名隐藏(重定义)的问题

"同名隐藏“:在基类和派生类中,如果派生类的函数和基类的函数同名,就会有同名隐藏。

如果派生类和基类中有同名成员,子类成员将屏蔽父类对同名函数的直接访问。(注意不要与函数重载混淆)

在这里插入图片描述

如果发生同名隐藏,那么通过对象来调用同名函数时,到底是调用子类还是父类的函数,这个是由指针的类型决定,而不是指针执行的对象的类型决定的。

解决同名隐藏问题:通过作用域限定符来访问 (基类::基类成员)

六.继承性

1.友元关系不能继承,基类友元不能访问子类私有和保护成员

2.父类定义static静态成员,则整个继承体系里面只有一个这样的成员

七.菱形继承

在谈菱形继承之前,需要先了解单继承和多继承:

  • 单继承是一个子类只有一个直接父类时称这个继承关系是单继承
  • 一个子类有两个或两个以上的直接父类时称这个继承关系为多继承 继承中子类中成员的排列次序与继承次序有关 (也就是说先继承的类,类中成员的地址越靠下)

菱形继承:两个子类同时继承一个父类,而又有子类同时继承这两个子类

缺点:导致数据冗余和二义性的问题

解决方法:

  1. 对造成二义性的属性使用域访问限定符,这样从本质上并没有解决二义性
  2. 想要解决二义性和数据冗余,这就需要用到虚拟继承。属性只会生成一份,要调用它需要使用虚基表指针,虚基表指针指向虚基表,虚基表中存在偏移量,通过偏移量就可以找到共有的那个属性。

虚拟继承

一般不会实现虚拟继承,一般是为了解决菱形继承中的二义性

class B
{
public:
	int _b;
};
class D : virtual public B//虚拟继承
{
public:
	int _d;
};
int main()
{
	cout << sizeof(D) << endl;//12
	D d;
	d._b = 1;
	d._d = 2;
	return 0;
}

在这里插入图片描述

在执行这段代码时,首先需要调用构造函数。从上图中看到,在构造对象期间,编译器给对象的前4个字节填充了数据。

而这一个过程只能在构造函数期间执行。

因此可以推断应该是编译器默认的构造函数所进行的操作。

cout << sizeof(D) << endl;改语句输出为12,比想象中的多了4个字节。

在这里插入图片描述

从反汇编中可以看对象时怎样赋值的。以给_b赋值为例

  • 第一个mov语句:把对象的前4个字节的内容获取
  • 第二个mov语句:我们可以把第一个mov语句中获取得d对象前4个字节的内容向下偏移4个字节里面的内容存到ecx中,具体过成如下图

在这里插入图片描述

  • 第三个mov语句:把1赋值到d对象偏移量为8的位置

而个子类自己的_d赋值时一条赋值语句就解决了,而在给基类的成员赋值时通过三条语句来进行的。

看完虚拟继承,接下来我们把虚拟继承放到菱形虚拟继承中来看

class B
{
public:
	int _b;
};
class C :virtual public B
{
public:
	int _c;
};
class D : virtual public B
{
public:
	int _d;
};
class A :public C, public D
{
public:
	int _a;
};
int main()
{
	cout << sizeof(A) << endl;//输出结果为24
	system("pause");
	return 0;
}

为什么它的大小是24个字节呢?下面给出它的对象模型如下就明白了

在这里插入图片描述

到此这篇关于C++中的继承方式与菱形继承解析的文章就介绍到这了,更多相关C++中的继承内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C语言putenv()函数和getenv()函数的使用详解

    C语言putenv()函数和getenv()函数的使用详解

    这篇文章主要介绍了C语言putenv()函数和getenv()函数的使用详解,用来进行环境变量的相关操作,需要的朋友可以参考下
    2015-09-09
  • QT+OpenCV实现录屏功能

    QT+OpenCV实现录屏功能

    这篇文章主要为大家详细介绍了QT+OpenCV实现录屏功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • C语言数组实现打砖块游戏

    C语言数组实现打砖块游戏

    这篇文章主要为大家详细介绍了C语言数组实现打砖块游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-05-05
  • C++高精度计时的几种方法总结(测试函数运行时间)

    C++高精度计时的几种方法总结(测试函数运行时间)

    本文介绍了C++中常用的几种程序计时方法,包括clock()函数、GetTickCount()、QueryPerformanceCounter()以及C++11中的chrono库函数,这篇文章主要介绍了C++高精度计时的几种方法,需要的朋友可以参考下
    2024-09-09
  • c++ lambda捕获this 导致多线程下类释放后还在使用的错误问题

    c++ lambda捕获this 导致多线程下类释放后还在使用的错误问题

    Lambda表达式是现代C++的一个语法糖,挺好用的。但是如果使用不当,会导致内存泄露或潜在的崩溃问题,这里总结下c++ lambda捕获this 导致多线程下类释放后还在使用的错误问题,感兴趣的朋友一起看看吧
    2023-02-02
  • C++利用GPAC实现生成MP4文件的示例代码

    C++利用GPAC实现生成MP4文件的示例代码

    GPAC主要针对学生和内容创作者,代表了一个跨平台的多媒体框架,开发人员可以使用它在 LGPL 许可下制作开源媒体。本文就来用GPAC实现生成MP4文件,感兴趣的可以了解一下
    2023-02-02
  • C++定时器实现和时间轮介绍

    C++定时器实现和时间轮介绍

    这篇文章主要介绍了C++定时器实现和时间轮介绍,定时器可以由很多种数据结构实现,比如最小堆、红黑树、跳表、甚至数组都可以,其本质都是拿到最小时间的任务,然后取出该任务并执行,更多相关内容介绍,需要的小伙伴可以参考一下
    2022-09-09
  • c语言中的二级指针做函数参数说明

    c语言中的二级指针做函数参数说明

    这篇文章主要介绍了c语言中的二级指针做函数参数说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-05-05
  • 详细对比C语言中的chmod()函数和fchmod()函数

    详细对比C语言中的chmod()函数和fchmod()函数

    这篇文章主要介绍了C语言中的chmod()函数和fchmod()函数的详细对比,两个都是用于修改文件权限但是请注意实际使用上的差异,需要的朋友可以参考下
    2015-09-09
  • 关于虚函数实现多态的原理及分析

    关于虚函数实现多态的原理及分析

    这篇文章主要介绍了C++中如何实现多态问题,具有很好的参考价值,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02

最新评论