版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
1.C++中的多重继承
- C++支持编写多重继承的代码
- 一个子类可以拥有多个父类
- 子类拥有所有父类的成员变量
- 子类继承所有父类的成员函数
- 子类对象可以当作任意父类对象使用(父子类有赋值兼容性原则)
- 多重继承的语法规则
-
class Derived : public BaseA,public BaseB,public BaseC{
-
//````
-
};
- 多重继承的本质与单继承相同!多重继承容易带来问题,在其他语言已经被遗弃。
2.多重继承问题一
- 通过多重继承得到的对象可以拥有“不同的地址”!!!
- 解决方案:无
- 原因分析(不同的父类指针指向子类中属于自己的那部分地址)
- 编程实验:多重继承问题一
-
#include <iostream>
-
-
using
namespace
std;
-
-
class BaseA
-
{
-
int ma;
-
-
public:
-
BaseA(
int a)
-
{
-
ma = a;
-
}
-
-
int getA()
-
{
-
return ma;
-
}
-
};
-
-
class BaseB
-
{
-
int mb;
-
-
public:
-
BaseB(
int b)
-
{
-
mb = b;
-
}
-
-
int getB()
-
{
-
return mb;
-
}
-
};
-
-
// 多继承
-
class Derived :
public BaseA,
public BaseB
-
{
-
int mc;
-
-
public:
-
Derived(
int a,
int b,
int c) :BaseA(a), BaseB(b)
// 初始化列表。
-
{
-
mc = c;
-
}
-
-
int getC()
-
{
-
return mc;
-
}
-
-
void print()
-
{
-
cout <<
"ma = " << getA() <<
", "
-
<<
"mb = " << getB() <<
", "
-
<<
"mc = " << mc <<
endl;
-
}
-
};
-
-
int main()
-
{
-
cout <<
"sizeof(Derived) = " <<
sizeof(Derived) <<
endl;
// 每个类私有变量的字节数加在一起
-
Derived d(1, 2, 3);
-
-
d.print();
-
-
cout <<
"d.getA() = " << d.getA() <<
endl;
-
cout <<
"d.getB() = " << d.getB() <<
endl;
// 用类的对象访问成员方法
-
cout <<
"d.getC() = " << d.getC() <<
endl;
-
-
cout <<
endl;
-
-
BaseA *pa = &d;
-
BaseB *pb = &d;
// 注意以上两行,都是将对象d的地址赋值给一个指针,表面上看似pa指针应该等于pb指针,
-
// 但实际上不会这样,pa指向的是d对象中BaseA的子对象,而pb指向的是d对象中BaseB子对象的部分。(这两部分并未重合)
-
cout <<
"pa->getA() = " << pa->getA() <<
endl;
// 1
-
cout <<
"pb->getB() = " << pb->getB() <<
endl;
// 2
-
-
cout <<
endl;
-
-
void *paa = pa;
-
void *pbb = pb;
-
-
if (paa == pbb)
-
{
-
cout <<
"point to the same Object" <<
endl;
-
}
-
else
-
{
-
cout <<
"ERROR" <<
endl;
-
}
-
-
cout <<
"pa = " << pa <<
endl;
-
cout <<
"pb = " << pb <<
endl;
-
cout <<
"paa = " << paa <<
endl;
-
cout <<
"pbb = " << pbb <<
endl;
-
-
system(
"pause");
-
-
return
0;
-
}
- 运行结果
3.多重继承的问题二
- 多重继承可能产生冗余的成员
- eacher、Student都有People类所有成员变量成员函数,Doctor类同时继承Teacher类、Student类,不现实?
- 编程实验:多重继承问题二
-
/*多重继承产生的问题2*/
-
#include <iostream>
-
-
using
namespace
std;
-
-
class People
-
{
-
string m_name;
-
int m_age;
-
public:
-
People(
string name,
int age)
-
{
-
m_name = name;
-
m_age = age;
-
}
-
void print()
-
{
-
cout <<
"Name = " << m_name <<
", "
-
<<
"Age = " << m_age <<
endl;
-
}
-
};
-
-
class Teacher :
public People
-
{
-
public:
-
Teacher(
string name,
int age) : People(name, age)
-
{
-
}
-
};
-
-
class Student :
public People
-
{
-
public:
-
Student(
string name,
int age) : People(name, age)
-
{
-
}
-
};
-
-
class Doctor :
public Teacher,
public Student
-
{
-
public:
-
Doctor(
string name,
int age) : Teacher(name +
"1", age +
1), Student(name +
"2", age +
2)
-
{
-
}
-
};
-
-
int main()
-
{
-
Doctor d("Nyist", 30);
-
-
//d.print();//error
-
-
d.Teacher::print();
//Name = Nyist1, Age = 31
-
d.Student::print();
//Name = Nyist2, Age = 32
-
-
return
0;
-
}
- 当多重继承关系出现闭合时将产生数据冗余的问题!!!!
- 解决方案:虚继承
- 虚继承能够解决数据冗余问题
- 中间层父类不用再关心顶层父类的初始化(但是中间层也要调用父类构造函数进行初始化。)
- 最终子类必须直接调用顶层父类(以及中间父类)的构造函数
-
#include <iostream>
-
#include <string>
-
-
using
namespace
std;
-
-
class People
-
{
-
string mName;
-
int mAge;
-
-
public:
-
People(
string name,
int age)
// 构造函数
-
{
-
mName = name;
-
mAge = age;
-
}
-
-
void print()
-
{
-
cout <<
"Name = " << mName <<
", "
-
<<
"Age = " << mAge <<
endl;
-
}
-
};
-
-
// 先看看虚继承,然后再撤销虚继承,中间类采用虚继承
-
class Teacher :
virtual
public People
-
{
-
public:
-
Teacher(
string name,
int age) : People(name, age)
// 构造函数,初始化列表
-
{
-
-
}
-
};
-
-
//中间类采用虚继承
-
class Student :
virtual
public People
-
{
-
public:
-
Student(
string name,
int age) : People(name, age)
-
{
-
-
}
-
-
};
-
// 博士类(一个博士可能即是老师,又是学生),采用直接继承,如果中间层的Teacher和Student不采用虚继承的话,
-
// 那在Doctor类中将有来自People类的mName,mAge等成员变量各两份,出现数据冗余现象,而且在子类Doctor中,
-
// 如果直接mName = 1, 会出现二义性的错误,因为编译器不知道mName到底是来自Teacher的还是Student类的。
-
class Doctor :
public Teacher,
public Student
-
{
-
public:
-
// 请注意,构造函数中的最后一个初始化People,也就是说采用虚继承的话,
-
// 则最终的子类仍需调用顶层父类的构造函数,这也是虚继承的一大问题,因为在实际开发中,有时很难确定最顶层的父类。
-
Doctor(
string name,
int age) :Teacher(name, age), Student(name, age), People(name, age)
-
{
-
-
}
-
};
-
-
// 各自私有属性是独立的
-
int main()
-
{
-
Doctor d("SantaClaus", 25);
// 先父类,在朋友,再自己
-
-
d.print();
-
-
system(
"pause");
-
-
return
0;
-
}
- 运行结果:
- 依然存在的问题:当架构设计中需要继承时,无法确定使用直接继承还是虚继承!!
4.小结
- C++支持多重继承的编程方式
- 多重继承容易带来问题
- 可能出现“同一个对象的地址不同”的情况
- 虚继承可以解决数据冗余的问题
- 虚继承使得架构设计可能出现问题