目录
- 继承的构造函数
- 多重继承
- 1.多重继承的概念
- 2.静态成员变量
- 3.派生类构造函数与析构函数
- 4.从多个父类继承构造函数
- 类型转换
- 虚基类、虚继承(虚派生)
- 总结
继承的构造函数
- C++语言同时支持单一继承和多重继承。单一继承是指派生类只从一个基类继承而来;相应的,多重继承指派生类同时从两个或更多的基类继承而来。
- 继承时,子类只能继承其直接基类(父类)的构造函数。默认(也即编译器自动给我们生成的)、拷贝、移动构造函数都是不能被继承的。那么怎么写继承的构造函数呢?
格式:using 类名::类名(构造函数名);
class A {
public:
A(int i,int j,int k){}
public:
static int m_static;
};
int A::m_static = 100; //后续要使用的话必须初始化,不使用的话可以不用定义
class B : public A {
public:
//B(int i,int j,int k):A(i,j,k) {};
using A::A;//继承A的构造函数,会把基类都生成与之对应的派生类构造函数
//B(int i,int j,int k):A(i,j,k) {};
//如果有默认参数的话,会构造多个派生类构造函数
//一个默认参数就会生成2个构造函数
//A(int i,int j,int k=5){} ;
//B(int i,int j,int k):A(i,j,k) {};
//B(int i,int j):A(i,j) {};
};
int main () {
B test(10,20,3);
return 1;
}
- 如果子类中只含有使用using 类名::类名;继承过来的构造函数时,编译器不认为我们给该子类定义了构造函数的。因此编译器还会为我们自动生成子类的默认构造函数
- 如果基类的构造函数中带有默认的参数值,那么编译器一遇到using A::A;时,就会帮我们在子类中构造出多个构造函数来.
多重继承
class grand
{
public:
grand(int v):m_valuegrad(v) {
cout << "grand的构造函数" << endl;
};
~grand() {
cout << "grand的析构函数" << endl;
}
void initData() {
cout << "grand initData" << endl;
}
void init() {
cout << "grand init" << endl;
}
static int valuegrand;
int m_valuegrad;
};
int grand::valuegrand = 100;
class A1 : public grand
{
public:
A1(int v):grand(v),m_valuea1(v) {
cout << "A1的构造函数" << endl;
};
~A1() {
cout << "A1的析构函数" << endl;
}
void initData() {
cout << "A1 initData" << endl;
}
int m_valuea1;
};
class B1
{
public:
B1(int v):m_valueb1(v) {
cout << "B1的构造函数" << endl;
};
~B1() {
cout << "B1的析构函数" << endl;
};
void initData() {
cout << "B1 initData" << endl;
}
int m_valueb1;
};
class C: public B1 ,public A1
{
public:
C(int v):B1(v),A1(v),m_valuec(v) {
cout << "C的构造函数" << endl;
};
~C() {
cout << "C的析构函数" << endl;
}
int m_valuec;
};
1.多重继承的概念
一个子类继承自多个(2个及以上)父类。
2.静态成员变量
int grand::valuegrand = 100;
后续要使用的话必须初始化,不使用的话可以不用定义。
类跟类对应的对象都可以使用。
int main () {
C c(1);
c.init();//会调用基类grand
c.A1::initData();//2个父类有同名函数需要标明具体类名
c.B1::initData();
c.valuegrand = 10000;
A1::valuegrand = 1000;
C::valuegrand = 1000;
cout << c.valuegrand << endl;
return 1;
}
3.派生类构造函数与析构函数
- 构造一个派生类对象将同时构造并初始化所有的直接基类的成分。
- 派生类的构造函数初始化列表只初始化它的直接基类,在多继承时也不例外。这样就会一层一层地把参数传递回最原始的基类,并把all的基类成分都构造好。
- 基类的构造顺序跟“派生列表”中基类的出现顺序是保持一致的!析构顺序则相反。
- 每个类的析构函数都只会进行自己这个类本身的成分的释放工作(类与类之间的析构函数是互不干扰的)。
4.从多个父类继承构造函数
class A {
public:
A(int tv) {}
};
class B {
public:
B(int tv) {}
};
class C : public A,public B {
public:
using A::A;//继承A类的构造函数 ==> C(int tv):A(tv){}
using B::B;//错误!继承B类的构造函数是 ==> C(int tv):B(tv){}该构造函数和继承自A类的一模一样
};
上述code中C多继承自父类A和父类B的构造函数已经重定义了。因此我们只能自己定义一个属于子类C的构造函数,应该在C中添加:
C(int tv):A(tv),B(tv){
cout << "C类的构造函数执行了!" << endl;
}
类型转换
基类指针是可以指向一个派生类(子类)对象的:因为编译器会帮助我们隐式地执行这种派生类到基类的转换。究其原因:因为每个派生类对象都会包含基类对象的成分。在多继承中,基类指针也是可以指向一个派生类(子类)对象的!
grand *g = new C(1);
A1 *a = new C(1);
B1 *b = new C(1);
C tc(2);
grand gg(tc);
这些写法都是正确的。
虚基类、虚继承(虚派生)
派生列表中,同一个基类只能出现一次,但是如下两种特殊情况例外:
- 派生类可以通过它的两个直接基类分别继承自同一个间接基类。
- 直接继承某个基类,然后通过另一个基类间接继承该类。
class grand
{
public:
grand(int v):m_valuegrad(v) {
cout << "grand的构造函数" << endl;
};
~grand() {
cout << "grand的析构函数" << endl;
}
void initData() {
cout << "grand initData" << endl;
}
void init() {
cout << "grand init" << endl;
}
static int valuegrand;
int m_valuegrad;
};
int grand::valuegrand = 100;
class A1 : public grand
{
public:
A1(int v):grand(v),m_valuea1(v) {
cout << "A1的构造函数" << endl;
};
~A1() {
cout << "A1的析构函数" << endl;
}
void initData() {
cout << "A1 initData" << endl;
}
int m_valuea1;
};
class A2 : public grand
{
public:
A2(int v):grand(v),m_valuea2(v) {
cout << "A2的构造函数" << endl;
};
~A2() {
cout << "A2的析构函数" << endl;
}
int m_valuea2;
};
class B1
{
public:
B1(int v):m_valueb1(v) {
cout << "B1的构造函数" << endl;
};
~B1() {
cout << "B1的析构函数" << endl;
};
void initData() {
cout << "B1 initData" << endl;
}
int m_valueb1;
};
class C: public B1 ,public A1 ,public A2
{
public:
C(int v):B1(v),A1(v),A2(v),m_valuec(v) {
cout << "C的构造函数" << endl;
};
~C() {
cout << "C的析构函数" << endl;
}
int m_valuec;
};
int main() {
C ccc(1);
//ccc.m_valuegrad = 100;
return 1;
}
运行结果为:
可以发现grand调用了2次构造2次析构函数。当调用共享基类的成员是会出现不明确错误。这就是多继承时对于基类成员变量的二义性问题
比如 ccc.m_valuegrad = 100; 提示C::m_valuegrad" 不明确。为了解决这样的错误同时为了提高效率,怎么才能调用一个呢?
只需在A1和A2继承grand的添加virtual。
class A1 :virtual public grand
class A2 :virtual public grand
同时把C(int v):B1(v),A1(v),A2(v),m_valuec(v)改为
C(int v):B1(v),A1(v),A2(v),gand(v),m_valuec(v)
修改之后再次运行结果为:
OK,完美!
总结
- 若非必要,请一定不要选择用多继承的方式来编写你的代码!十分重要到建议:能用单继承解决问题,就不要用多继承!能不用virtual虚继承就尽量不用virtual继承来写代码!
- 若实在必要用到多继承时,提醒自己到底是否需要用虚继承的方式来进行多继承!(当产生成员变量的二义性问题时,就需要用虚继承来进行多继承!)。
- 学习多继承这个知识点不是说你一定要去常用它,而是为了让你去阅读别人的代码时不发懵!