飞道的博客

继承

304人阅读  评论(0)

继承

概念
继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。继承是类设计层次的复用。

继承方式
public继承、protected继承、private继承
注意: 在实际运用中一般使用都是public继承,几乎很少使用protetced/private继承,也不提倡使用protetced/private继承,因为protetced/private继承下来的成员都只能在派生类的类里面使用,实际中扩展维护性不强。

赋值兼容规则(必须是public的继承方式)
public继承方式:可以将一个子类的对象看成是一个基类对象;在类外所有使用基类对象的位置都可以使用子类对象代替
对象模型:对象中各个成员变量在内存中的布局方式;
1.可以使用子类对象给基类对象来进行赋值,反之则不行;
2.可以使用基类的指针或引用指向子类的对象;
3.不能使用子类的指针或引用指向基类的对象;
同名隐藏
概念:在继承体系,子类和基类具有相同名称的成员(成员变量||成员函数),如果使用子类对象访问相同名称的成员,优先访问到的是子类自己的,基类相同名称的成员无法访问到。
注意:

  • 成员函数发生隐藏,与函数原型是否相同没有关系;
  • 成员变量发生隐藏,与成员变量的类型是否相同没有关系;

在继承体系中子类对象构造过程
注意:

  • 基类如果没有定义任何构造函数,则子类可以定义也可以不用定义
  • 如果基类显式定义了无参的构造函数或全缺省的构造函数,则子类可以根据自己的需求选择给出对应的构造函数,即:可以定义也可以不用定义;如果子类没有显式定义时,则编译器可以替用户实现一个默认的构造函数,目的:将子类对象从基类继承下来的成员构造完整。
  • 如果基类显式定义了构造函数,并且构造函数不是无参或全缺省的构造函数,则子类必须要显式定义自己的构造函数,然后需要在其构造函数初始化列表的位置显式调用基类构造函数完成基类部分成员的初始化,否则代码就编译失败
    菱形继承&二义性问题及解决
    单继承:一个子类只有一个父类;
    多继承:一个子类具有多个父类;
    菱形继承:两个子类继承同一个父类,而又有子类同时继承这两个子类;
class A
{
public:
	int _a;
};
class B:public A
{
public:
	int _b;
};
class C:public A
{
public:
	int _c;
};
class D:public B,public C
{
public:
	int _d;
}
int main()
{
	D d;
	d._a = 10;
	//调用出现错误,堆_a访问不明确
	d._b = 2;
	d._c = 3;
	d._d = 4;
}

菱形继承二义性解决方式:
1.让访问明确化,在调用时加上类的域名;
2.让最顶层基类中成员在子类中只存储一份(菱形虚拟继承);

虚拟继承:只需在继承权限前加virtual;
虚拟继承和普通继承的区别:
1.虚拟继承对象中多了4个字节
2.如果用户没有显式定义构造函数,则编译器会给子类生成一份默认的构造函数;或者如果子类显式定义了构造函数,则编译器会对子类构造函数进行修改(向对象前4个字节中填充数据);
3.对象模型布局方式不一样;

注意:
对于一般的单继承,是不会使用虚拟继承方式的;
虚拟继承方式唯一作用:解决菱形继承二义性问题;

继承作用
1.实现代码的复用;
2.实现多态;
注意:继承可以实现代码复用,但是如果只是复用代码,优先不考虑继承,而是优先考虑组合(聚合);


转载:https://blog.csdn.net/independenting/article/details/113774619
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场