С++: множественное наследование с полиморфизмом
(заранее извините вопрос о нобе)
У меня есть 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?
- Если да, то почему компилятор не позволяет мне присваивать объект переменной типа своего суперкласса?
- Если нет, почему бы и нет; и что было бы правильным путем для этого?
Приветствия
РЕДАКТИРОВАТЬ: Упреждающий, этот вопрос НЕ совпадает с одним из следующих:
Полиморфизм связывает наследование
Наследование, преследующее полиморфизм в С++?
Ответы
Ответ 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 Фактически пройдите весь этот раздел.