Подтвердить что ты не робот

С++: множественное наследование с полиморфизмом

(заранее извините вопрос о нобе)

У меня есть 4 класса:

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

По существу Person - это базовый класс, который непосредственно подклассифицирован как Student, так и Employee. StudentEmployee использует множественное наследование для подкласса как 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?

  • Если да, то почему компилятор не позволяет мне присваивать объект переменной типа своего суперкласса?
  • Если нет, почему бы и нет; и что было бы правильным путем для этого?

Приветствия


РЕДАКТИРОВАТЬ: Упреждающий, этот вопрос НЕ совпадает с одним из следующих:
Полиморфизм связывает наследование
Наследование, преследующее полиморфизм в С++?

4b9b3361

Ответ 1

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 {};

Это исправит вашу ошибку.

Есть и другая большая проблема с вашим кодом, и он называется slicing.

Когда вы это сделаете:

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};

Ответ 2

Существует два одинаково возможных пути от объекта типа StudentEmployee как Person.

Вам нужно использовать ключевое слово virtual для классов Student и Employee. См. Часто задаваемые вопросы 25.8 Фактически пройдите весь этот раздел.