C++ 多继承
程序员文章站
2024-03-05 18:40:01
...
写在前面
在腾讯面试时,面试官问:
- C++里面子类可以继承多个父类吗?(可以)
- 子类如果继承多个父类需要注意什么问题?(有点不知从何答起)
- 父类A,父类B,子类C继承父类A和父类B,父类A和父类B中有都有函数fun,在子类C中如何处理?
多继承
多继承是指从多个直接基类中产生派生类,多继承的派生类继承了所有父类的成员。
多继承中构造函数和析构函数的执行顺序:
- 在派生类中,基类的构造函数的调用顺序和在派生类构造函数中出现的顺序无关,和派生类在声明时,基类的出现顺序有关
- 析构顺序:和构造顺序正好相反
#include <iostream>
using namespace std;
//基类
class BaseA{
public:
BaseA(int a, int b);
~BaseA();
protected:
int m_a;
int m_b;
};
BaseA::BaseA(int a, int b): m_a(a), m_b(b){
cout<<"BaseA constructor"<<endl;
}
BaseA::~BaseA(){
cout<<"BaseA destructor"<<endl;
}
//基类
class BaseB{
public:
BaseB(int c, int d);
~BaseB();
protected:
int m_c;
int m_d;
};
BaseB::BaseB(int c, int d): m_c(c), m_d(d){
cout<<"BaseB constructor"<<endl;
}
BaseB::~BaseB(){
cout<<"BaseB destructor"<<endl;
}
//派生类
class Derived: public BaseA, public BaseB{
public:
Derived(int a, int b, int c, int d, int e);
~Derived();
public:
void show();
private:
int m_e;
};
Derived::Derived(int a, int b, int c, int d, int e): BaseB(c, d), BaseA(a, b), m_e(e){
cout<<"Derived constructor"<<endl;
}
Derived::~Derived(){
cout<<"Derived destructor"<<endl;
}
void Derived::show(){
cout<<m_a<<", "<<m_b<<", "<<m_c<<", "<<m_d<<", "<<m_e<<endl;
}
int main(){
Derived obj(1, 2, 3, 4, 5);
obj.show();
return 0;
}
运行结果:
BaseA constructor
BaseB constructor
Derived constructor
1, 2, 3, 4, 5
Derived destructor
BaseB destructor
BaseA destructor
多继承容易出现的问题: 命名冲突(成员变量名、成员函数名)
类A派生出类B和类C,类D继承自类B和类C,此时类A中的成员变量和成员函数集成到类D中变成了两份(A->B->D;A->C->D)。加入类A中有一个成员变量a,在类D中进行访问就会产生歧义,编译器不知道究竟来自A->B->D,还是来自A->C->D
//间接基类A
class A{
protected:
int m_a;
};
//直接基类B
class B: public A{
protected:
int m_b;
};
//直接基类C
class C: public A{
protected:
int m_c;
};
//派生类D
class D: public B, public C{
public:
void seta(int a){ m_a = a; } //命名冲突
void setb(int b){ m_b = b; } //正确
void setc(int c){ m_c = c; } //正确
void setd(int d){ m_d = d; } //正确
private:
int m_d;
};
int main(){
D d;
return 0;
}
说明:在类D 中直接访问成员变量m_a会发生错误,这里可以指名成员变量属于哪个类,例如B::m_a或者C::m_a。那还有其他的解决办法吗??虚继承
虚继承
为了解决多继承中的命名冲突和数据冗余的问题,C++中提出了虚继承,使得在派生类中只保留一份间接基类的成员
//间接基类A
class A{
protected:
int m_a;
};
//直接基类B
class B: virtual public A{ //虚继承
protected:
int m_b;
};
//直接基类C
class C: virtual public A{ //虚继承
protected:
int m_c;
};
//派生类D
class D: public B, public C{
public:
void seta(int a){ m_a = a; } //正确
void setb(int b){ m_b = b; } //正确
void setc(int c){ m_c = c; } //正确
void setd(int d){ m_d = d; } //正确
private:
int m_d;
};
int main(){
D d;
return 0;
}
虚继承的目的是让某个类做出声明,承诺愿意共享它的基类。其中,这个被共享的基类就称为虚基类(Virtual Base Class),本例中的 A 就是一个虚基类。在这种机制下,不论虚基类在继承体系中出现了多少次,在派生类中都只包含一份虚基类的成员。
必须在虚派生的真实需求出现前就已经完成虚派生的操作。在上图中,当定义 D 类时才出现了对虚派生的需求,但是如果 B 类和 C 类不是从 A 类虚派生得到的,那么 D 类还是会保留 A 类的两份成员。
换个角度讲,虚派生只影响从指定了虚基类的派生类中进一步派生出来的类,它不会影响派生类本身。
结论
回到刚开始的问题
- 在多继承中需要注意的就是命名冲突和冗余数据
- 针对开篇提到的问题:父类A,父类B,子类C继承父类A和父类B,父类A和父类B中有都有函数fun,在子类C中如何处理?
如果定义一个类C的对象,该对象调用函数fun时会出现二义性的问题,不知道要调用哪一个父类中的函数。这时候可以在类C中定义同名函数,指定是调用哪一个类中的fun
#include<bits/stdc++.h>
using namespace std;
class A{
public:
void print(){
cout << "A print";
}
};
class B{
public:
void print(){
cout << "B print";
}
};
class C: public A, public B{
public:
void print(){
B::print();
}
};
int main(){
C t;
t. print();
return 0;
}
#include <iostream>
using namespace std;
//基类
class BaseA{
public:
BaseA(int a, int b);
~BaseA();
public:
void show();
protected:
int m_a;
int m_b;
};
BaseA::BaseA(int a, int b): m_a(a), m_b(b){
cout<<"BaseA constructor"<<endl;
}
BaseA::~BaseA(){
cout<<"BaseA destructor"<<endl;
}
void BaseA::show(){
cout<<"m_a = "<<m_a<<endl;
cout<<"m_b = "<<m_b<<endl;
}
//基类
class BaseB{
public:
BaseB(int c, int d);
~BaseB();
void show();
protected:
int m_c;
int m_d;
};
BaseB::BaseB(int c, int d): m_c(c), m_d(d){
cout<<"BaseB constructor"<<endl;
}
BaseB::~BaseB(){
cout<<"BaseB destructor"<<endl;
}
void BaseB::show(){
cout<<"m_c = "<<m_c<<endl;
cout<<"m_d = "<<m_d<<endl;
}
//派生类
class Derived: public BaseA, public BaseB{
public:
Derived(int a, int b, int c, int d, int e);
~Derived();
public:
void display();
private:
int m_e;
};
Derived::Derived(int a, int b, int c, int d, int e): BaseA(a, b), BaseB(c, d), m_e(e){
cout<<"Derived constructor"<<endl;
}
Derived::~Derived(){
cout<<"Derived destructor"<<endl;
}
void Derived::display(){
BaseA::show(); //调用BaseA类的show()函数
BaseB::show(); //调用BaseB类的show()函数
cout<<"m_e = "<<m_e<<endl;
}
int main(){
Derived obj(1, 2, 3, 4, 5);
obj.display();
return 0;
}
运行结果:
BaseA constructor
BaseB constructor
Derived constructor
m_a = 1
m_b = 2
m_c = 3
m_d = 4
m_e = 5
Derived destructor
BaseB destructor
BaseA destructor
上一篇: JDBC链接数据库的几个步骤