C++学习笔记 ---继承

继承概述(为什么出现继承)

作为面向对象三大特性之一,继承的好处是可以减少重复的代码。比如,我们在建立一个比较大的网站时,网站中有很多页面,每个页面其实是有一些相同的东西的,比如标题栏,导航栏还是广告等等。如果我们在写每个页面时都把这些公共的部分重新写一遍,代码会非常累赘,我们可以把公共的部分封装为一个类(父类),后面的页面去继承这个类,这样公共部分的代码只需要写一遍,后面需要继承即可,便减少了许多代码。

继承中的对象模型

问题:从父类继承过来的成员,哪些属于子类对象中?

//父类(基类)
class Base {
public:
 int m_A;
protected:
 int m_B;
private:
 int m_C;
};
//子类(派生类)
class Son: public Base {
public:
 int m_D;
};
void test01() {
 Son s1;
 cout << sizeof(s1) << endl;
}

打印结果为16

这里主要是想验证父类中私有成员是否被子类继承下去了。打印结果说明答案是肯定的

进一步验证
打开visual studio Developer Command Prompt

首先定位到当前CPP文件的盘符
在这里插入图片描述
然后输入cl/d1 reportSingleClassLayout查看的类名 所属文件名
注意cl(这个是大写字母L的小写l)
d1(这个是数字1)

在这里插入图片描述结果如下:

在这里插入图片描述结论:父类中私有成员也是被子类继承下去了,只是由编译器给隐藏后访问不到

继承中构造和析构顺序

子类继承父类后,当创建子类对象,也会调用父类的构造函数
问题:父类和子类的构造和析构顺序是谁先谁后?

class Base {
public:
 Base() {
  cout << "父类构造函数" << endl;
 }
 ~Base() {
  cout << "父类析构函数" << endl;
 }
};
class Son: public Base {
public:
 Son() {
  cout << "子类构造函数" << endl;
 }
 ~Son() {
  cout << "子类析构函数" << endl;
 }
};
void test01() {
 Son s1;//实例化一个对象
}

打印结果:

在这里插入图片描述
结论:继承中,实例化子类对象时,先调用父类构造函数,再调用子类构造函数,析构顺序与构造顺序是相反的

菱形继承问题以及解决方法

概念:

两个派生类(子类)继承同一个基类(父类),又有某个类同时继承这两个派生类(子类)这种继承称为菱形继承
假如现在有 A B C D四个类 以下就是菱形继承
在这里插入图片描述

带来的问题:

class A {
public:
 int m_Age;
};
class B: public A {};
class C: public A {};
class D: public B, public C {};
void test01() {
 D d1;
 d1.B::m_Age = 10;
 d1.C::m_Age = 12;
 cout << d1.B::m_Age << endl;
 cout << d1.C::m_Age << endl;
}

打印结果:这个很好理解,同名的成员变量 想要输出的话加作用域区分即可

但是问题是如果我们想打印输出D类中的数据 呢

d1.m_Age //因为d1是D类实例化得来的 
//所以想要输出同名成员变量直接输出即可 
//无需加作用域区分

在这里插入图片描述
它会报错,因为D类继承了B,C 类,也就是说它继承 了A类的m_Age继承了两份。那么就会出现二义性问题。它不知道是输出B类的还是C类的。也就是说,我们只需要一份数据即可,不能同时要两份。因此,菱形继承带来的问题是子类继承了两份相同的数据,导致了资源浪费以及毫无意义

解决办法(利用虚继承):

利用虚继承可以解决菱形继承的问题。语法很简单`

//继承前加上virtual关键字就变为了虚继承
//此时它们的公共父类A就变为了虚基类(虚父类)
class B: virtual public A {};
class C: virtual public A {};
class D: public B, public C {};

day在这里插入图片描述根据打印结果 显然虚继承之后 m_Age这个数据只有一份了。继承下来的也只有一份。以最近一次赋值为值

原理剖析:

运用命令提示符查看D类的对象模型:
结果如下:
在这里插入图片描述
这是没有用到虚继承时D类的对象模型 很显然它继承了两份相同的数据,所以会出现二义性在这里插入图片描述

分析之前先解释两个名词:
vbptr(虚基类指针):
v:virtual(虚拟)
b:base(基类)
ptr:pointer(指针)
它指向的地址是一个虚基类表

vbtable(虚基类表) :table是表格的意思
里面记录了偏移量

分析如下:
显然,当是虚继承时,数据只有一份了,它继承于A类.D类在继承B C类时,是继承了两个指针.它们对应的有相应的偏移量.比如B类vbptr初值为0它会找到对应的虚基类表,虚基类表中记录的偏移量是8 那么0 + 8 = 8 就会对应从A类继承来的m_Age,C类同理,vbptr初值是4,偏移量是4,4 + 4 = 8 它也能对应地找到m_Age的地址.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值