C++继承

一:什么是继承?它的表现形式是什么样子的?

继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能。这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。
:继承关系和访问限定符
三种成员访问限定符public(公有)  private(私有) protected(保护)对应的继承关系也有三种,public(公有继承)  private(私有继承) protected(保护继承)
三种访问限定符实际的作用就是 对于派生类访问基类成员的一种保护形式,对于不同的继承关系,相对于派生类而访问基类成员的权限发生了一些改变


1: public

公有继承,其代表着派生类原原本本的继承来自父类的数据并且对于基类的非私有成员访问属性都不变。
2:protected
保护继承,基类非私有成员都成为派生类的保护成员
3:private
私有继承,基类中的所有成员都成为派生类的私有成员
4: 总结
我们将访问限定符 private   protected  public  的权限看由大到小的,对于给定的继承关系      class Base : acess_label  Derive{};
对于基类成员中访问限定符 小于 acess_label 的成员的访问限定符在派生类中看做acess_label ,并且派生类继承基类的私有成员都不可见,即存在却不可用

1.基类的private成员在派生类中是不能被访问的,如果基类成员不想在类外直接被访问,但需要 在派生类中能访问,就定义为protected。可以看出保护成员限定符是因继承才出现的。
2.public继承是一个接口继承,保持is-a原则,每个父类可用的成员对子类也可用,因为每个子类对象也都是一个父类对象。
3.protected/private继承是一个实现继承,基类的部分成员并非完全成为子类接口的一部分,是 has-a 的关系原则,所以非特殊情况下不会使用这两种继承关系,在绝大多数的场景下使用的都是公有继承。私有继承以为这is-implemented-in-terms-of(是根据……实现的)。通常比组合(composition)更低级,但当一个派生类需要访问基类保护成员或需要重定义基类的虚函数时它就是合理的。
4.不管是哪种继承方式,在派生类内部都可以访问基类的公有成员和保护成员,基类的私有成员存在但是在子类中不可见(不能访问)。
5.使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最好显示的写出继承方式。
6.在实际运用中一般使用都是public继承,极少场景下才会使用protetced/private继承.

三:派生类中默认的成员函数
class Base
{
public:
	Base()
	{
		cout << "B()" << endl;
	}
	~Base()
	{
		cout << "~B()" << endl;
	}

private:
	int _pri;
protected:
	int _pro;
public:
	int _pub;
};
class Derived :public Base
{
public:
	Derived()
	{
		cout << "D()" << endl;
	}
	~Derived()
	{
		cout << "~D()" << endl;
	}

private:
	int _d_pri;
protected:
	int _d_pro;
public:
	int _d_pub;
};

int main()
{

	Derived d;
	return 0;
}

1: 构造函数

那么基类和派生类的构造函数谁先调用呢?
验证:

分析:
先调用派生类的构造函数,在派生类的构造函数初始化列表中调用基类的构造函数,
初始化列表完毕后,在调用派生类的构造函数体

2:析构函数
那么基类和派生类的析构函数谁先调用呢?
验证:

分析:
实际上这种普通的继承关系模型是这样的,在派生类里面包含着一个基类, 个整
体就是一个派生类的模型,底层存放着派生类自己的数据
构造函数中我们了解到先是派生类的构造函数,在其里面执行了基类的构造函
那么析 构的时候按照先调用派生类的析构函数清理派生类独有的数据,再调用基类析
构函数,清理基类的数据

3:继承体系中隐藏
什么是继承体系中隐藏呢?子类和父类中有同名成员,子类成员将屏蔽父类对成员
的直接访问。(在子类成员函数中,可以使用 基类::基类成员 访问)--隐藏 --重定义
class Base
{
public:
	int _pub;
};
class Derive :public Base
{
public:
	int _pub;
};

int main()
{
	Derive d;
	d._pub = 2;
	return 0;
}



总结:
①. 在继承体系中基类和派生类是两个不同作用域。
②. 子类和父类中有同名成员,子类成员将屏蔽父类对成员的直接访问。(在子类成员函
数中,可以使用 基类::基类成员 访问)--隐藏 --重定义
③. 注意在实际中在继承体系里面最好不要定义同名的成员。

4:继承与转换--赋值兼容规则--public继承
①. 子类对象可以赋值给父类对象(切割/切片)
②. 父类对象不能赋值给子类对象
③. 父类的指针/引用可以指向子类对象
④. 子类的指针/引用不能指向父类对象(可以通过强制类型转换完成)

5:友元与继承
友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员。

)单继承,多继承,菱形
1:单继承
2:多继承
class Student
{
public:
	int _s;
};

class Teacher
{
public:
	int _t;
};

class Assistant :public Student, public  Teacher
{
public:
	int _a;
};

int main()
{
	Assistant a;
	a._s = 1;
	a._t = 2;
	a._a = 3;
	return 0;
}

多继承实际上的内存存储模型如图所示,其继承模型和派生类继承基类的顺序有关
,谁在先,谁的模型在上

3:普通菱形继承

class Person
{
public:
	int _p;
};

class Student: public Person
{
public:
	int _s;
};

class Teacher: public Person
{
public:
	int _t;
};

class Assistant :public Student, public  Teacher
{
public:
	int _a;
};

int main()
{
	Assistant a;
	cout << sizeof(a) << endl;
	a.Student::_p = 11;
	a.Teacher::_p = 10;
	a._s = 1;
	a._t = 2;
	a._a = 3;
	return 0;
}

菱形继承模型

分析:
实际上,对于这种菱形继承,针对Student 和 Teacher 两个类种分别拥有一
个Person类,隶属于不同的作用域

4:菱形虚拟继承
class Person
{
public:
	int _p;
};

class Student: virtual public Person
{
public:
	int _s;
};

class Teacher:virtual public Person
{
public:
	int _t;
};

class Assistant :public Student, public  Teacher
{
public:
	int _a;
};

int main()
{
	Assistant a;
	cout << sizeof(a) << endl;
	a._p = 10;
	a._s = 1;
	a._t = 2;
	a._a = 3;
	return 0;
}
实际上,虚拟菱形继承和普通菱形继承的差异就在最顶端基类的分布情况,在普通
继承 中,Student 和Taecher两个类各自有一份Person类,这样就大大的浪费了空间,
而虚拟菱形继承Person类只有一份而且空间分布情况大有不通

分析:在内存窗口中明显的可以看到空间布局情况,但有8个字节放着 cc cc f7 00
和 e8 cc f7 00,这两个是什么呢?看起来有点像地址,我们则把它分别输入到内存窗口
中则得到左下角两个图,经过转化发现分别发现里面的数值是(0 12)和(0 20),
实际上这就是偏移量表,代表着 地址 相对自己的偏移量和 相对于Person类实体的偏移量
,这样就大大的节省了空间 ,

实际赋值就是先取 a中第一张偏移量表的地址,然后经过加上偏移量来进行赋值


5:菱形虚拟继承和普通菱形继承优缺点对比

缺点:
1:菱形虚拟继承模型所占内存大小比普通菱形继承大
2:普通菱形继承存在二义性和数据冗余问题
优点:
菱形虚拟继承解决了二义性和数据冗余的问题





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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值