问题 C ++:具有多态性的多重继承


(事先原谅noob问题)

我有4节课:

class Person {};
class Student : public Person {};
class Employee : public Person {};
class StudentEmployee : public Student, public Employee {};

实质上 Person 是基类,由两者直接子类化 Student 和 EmployeeStudentEmployee 使用多重继承来子类化 Student 和 Employee

Person pat = Person("Pat");
Student sam = Student("Sam");
Employee em = Employee("Emily");
StudentEmployee sen = StudentEmployee("Sienna");


Person ppl[3] = {pat, sam, em};
//compile time error: ambiguous base class
//Person ppl[4] = {pat, sam, em, sen}; 

当我使用数组 Person,基类,我可以把 Person 以及该数组中的所有子类。除了 StudentEmployee,鉴于基础模糊的原因。

鉴于 StudentEmployee 保证拥有的所有方法和属性 Person是的 StudentEmployee 被认为是Person的子类?

  • 如果是这样,为什么编译器不允许我将对象分配给其超类类型的变量?
  • 如果没有,为什么不呢;什么是实现这一目标的正确方法?

干杯


编辑:抢先一步,这个问题与以下任何一个问题都不一样:
多态性涉及继承
继承抄袭C ++中的多态? 


11358
2017-08-22 10:30


起源



答案:


StudentEmployee 肯定是一个子类 Person。问题是它是如此 两次:它间接继承 Person 两次(一次通过 Student 并且一旦通过 Employee)这就是为什么你得到“模糊的基类”错误。确保;确定 StudentEmployee 只是继承 Person 曾经,你必须使用 虚拟继承,像这样:

class Person {};
class Student : public virtual Person {};
class Employee : public virtual Person {};
class StudentEmployee : public Student, public Employee {};

这将解决您的错误。

但是,您的代码还有另一个大问题,而且它被称为 切片

当你这样做:

Person ppl[3] = {pat, sam, em};

三个数组 Person 将创建对象,但这些对象将使用隐式定义的复制构造函数进行复制 Person 类。现在,问题在于数组中的对象将是正确的 Person 对象而不是您希望它们的子类的对象。

要解决这个问题,你必须制作一个指针数组 Person 对象,像这样:

Person* ppl[] = {new Person("Pat"), new Student("Sam"),
                 new Employee("Emily"), new StudentEmployee("Sienna")};

要么

Person* ppl[] = {&pat, &sam, &em, &sen};

13
2017-08-22 10:53



但是,显然,像这样调用new几乎肯定会导致内存泄漏 - Falmarri
切片为+1。如果bguiz还不知道,这也可能是Person * ppl [] = {&pat,&sam,&em,&sen}; - 这两个选项的内存管理略有不同。 - Michael
@Falmarri:为什么?你仍然有指针数组。 - Job
@Michael:谢谢,补充说到我的回答。 - Job
@Michael:很好看:)原始指针表明内存属于其他地方。 - Matthieu M.


答案:


StudentEmployee 肯定是一个子类 Person。问题是它是如此 两次:它间接继承 Person 两次(一次通过 Student 并且一旦通过 Employee)这就是为什么你得到“模糊的基类”错误。确保;确定 StudentEmployee 只是继承 Person 曾经,你必须使用 虚拟继承,像这样:

class Person {};
class Student : public virtual Person {};
class Employee : public virtual Person {};
class StudentEmployee : public Student, public Employee {};

这将解决您的错误。

但是,您的代码还有另一个大问题,而且它被称为 切片

当你这样做:

Person ppl[3] = {pat, sam, em};

三个数组 Person 将创建对象,但这些对象将使用隐式定义的复制构造函数进行复制 Person 类。现在,问题在于数组中的对象将是正确的 Person 对象而不是您希望它们的子类的对象。

要解决这个问题,你必须制作一个指针数组 Person 对象,像这样:

Person* ppl[] = {new Person("Pat"), new Student("Sam"),
                 new Employee("Emily"), new StudentEmployee("Sienna")};

要么

Person* ppl[] = {&pat, &sam, &em, &sen};

13
2017-08-22 10:53



但是,显然,像这样调用new几乎肯定会导致内存泄漏 - Falmarri
切片为+1。如果bguiz还不知道,这也可能是Person * ppl [] = {&pat,&sam,&em,&sen}; - 这两个选项的内存管理略有不同。 - Michael
@Falmarri:为什么?你仍然有指针数组。 - Job
@Michael:谢谢,补充说到我的回答。 - Job
@Michael:很好看:)原始指针表明内存属于其他地方。 - Matthieu M.


类型对象有两条同样可能的路径 StudentEmployee 成为一个 Person

您需要使用关键字 virtual 对彼此而言 Student 和 Employee 类。看到 常见问题25.8 事实上,通过整个部分。


3
2017-08-22 10:34



谢谢你,那篇文章击中了头! - bguiz