1、c++继承关于子类的默认函数的写法
如果子类没有定义构造方法,则调用父类的无参数的构造方法
如果子类定义了构造方法,不论是无参数还是带参数,在创建子类的对象的时候,首先执行父类的构造方法,然后在执行自己的构造方法
在创建子类对象的时候,如果子类的构造函数没有显示调用父类的构造函数,则会调用父类的默认无参数构造函数
在创建子类对象的时候,如果子类的构造函数没有显示调用父类的构造函数且父类只定义了自己的有参构造函数,则会出错(如果父类只有有参数的构造方法,则子类必须显示调用此带参构造方法)。
如果子类调用父类带参数的构造方法,则需要父类的构造函数
赋值兼容(前提:public 继承权限)
1、派生类对象可以直接赋值给基类对象
2、基类对象的指针或引用可以指向派生类对象
同名隐藏
在继承体系中基类和派生类都有自己独立的作用域。
子类和父类中有同名成员,子类成员将屏蔽父类对成员的直接访问,
(在子类当中可以使用基类::基类成员访问),隐藏重定义。
在实际中在继承体系当中最好不要用同名成员
与同名隐藏相像的就是钻石继承问题,要区分开。同名隐藏是在基类和派生类里有相同的成员变量或者是成员函数。而钻石继承是相对于最后一个派生类而言,它的两个基类里有相同的成员函数或成员变量。
继承
2、分析菱形继承的问题
单继承:一个子类只有一个直接父类时称这个继承关系为单继承
#pragma once
#include<iostream>
using namespace std;
class A
{
public:
int _a;
};
class B : public A
{
public:
int _b;
};
void Test()
{
B b;
b._a = 1;
b._b = 2;
}
图解:
多继承:一个子类有两个或以上直接父类时称这个继承关系为多继承
#pragma once
#include<iostream>
using namespace std;
class A1
{
public:
int _a1;
};
class A2
{
public:
int _a2;
};
class B : public A1, public A2
{
public:
int _b;
};
void Test()
{
B b;
b._a1 = 1;
b._a2 = 2;
b._b = 3;
}
如图
菱形继承是建立在多继承的基础上。菱形继承:也称多边形继承
菱形继承:两个子类同时继承一个父类,而又有子类同时继承这两个子类
#pragma once
#include<iostream>
using namespace std;
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;
};
void Test()
{
D d;
d.B::_a = 1;//二义性问题的第一种解决方法(域限定符)
d.C::_a = 2;
d._b = 3;
d._c = 4;
d._d = 5;
}
程序运行结果
从内存中看到菱形继承派生而立的对象模型
理解钻石继承
#pragma once
#include<iostream>
using namespace std;
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;
};
void Test()
{
D d;
d._a = 1;
}
3、分析虚拟继承是怎么解决二义性和数据冗余的
虚拟继承是一种机制,类通过虚拟继承指出它希望共享虚基类的状态。对给定的虚基类,无论该类在派生层次中作为虚基类出现多少次,只继承一个共享的基类对象,共享基类子对象称为虚基类。虚基类用virtual声明继承关系,这样D就只有A的一份拷贝。
如果B类和C类对象在分别继承A类时都用virtual来标注,对于D类对象,C++会保证只有一个A的子类的字对象会被创建。
#pragma once
#include<iostream>
using namespace std;
class A
{
public:
int _a;
};
class B : virtual public A
{
public:
int _b;
};
class C : virtual public A
{
public:
int _c;
};
class D :public B, public C
{
public:
int _d;
};
void Test()
{
D d;
d._a = 1;
d._a = 2;
d._b = 3;
d._c = 4;
d._d = 5;
}
通过监视窗口看到对_a赋值B类和C类的_a都会被改变说明在D类中的对象模型中只存在一个_a,这样即解决了二义性问题又解决了数据冗余的问题。
菱形虚拟继承的实现原理
从内存中我们得到
发现内存里多了偏移量地址
虚继承解决了在菱形继承中子类对象包含多份父类对象的数据冗余问题,菱形继承解决了数据冗余的问题的同时也带来的性能上的损耗