17

(pardon the noob question in advance)

I have 4 classes:

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

Essentially Person is the base class, which are directly subclassed by both Student and Employee. StudentEmployee employs multiple inheritance to subclass both Student and 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}; 

When I use an array of Person, the base class, I can put Person and all of its subclasses inside this array. Except for StudentEmployee, given the reason ambiguous base class.

Given that StudentEmployee is guaranteed to have all the methods and attributes of Person, is StudentEmployee considered a subclass of Person?

  • If so, Why does the compiler not allow me to assign an object to a variable of the type of its superclass?
  • If not, why not; and what would be the proper way to accomplish this?

Cheers


EDIT: Preemptively, this question is NOT the same as either of the following:
polymorphism relates inheritance
Inheritance mucking up polymorphism in C++?

2 Answers 2

16

StudentEmployee certainly is a subclass of Person. The problem is it is so twice: It indirectly inherits Person twice (once through Student and once through Employee) and that's why you get the "ambiguous base class" error. To make sure StudentEmployee only inherits Person once, you have to use virtual inheritance, like so:

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

This will fix your error.

There is another big problem with your code, though, and it's called slicing.

When you do this:

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

An array of three Person objects will be created but those objects will be copy constructed using the implicitly defined copy constructor of the Person class. Now, the problem with this is that the objects in your array will be just Person objects and not objects of the subclasses you want them to be.

To fix this, you'll have to make an array of pointers to Person objects, like this:

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

or

Person* ppl[] = {&pat, &sam, &em, &sen};
Sign up to request clarification or add additional context in comments.

8 Comments

But, obviously, calling new like that will almost certainly lead to a memory leak
+1 for the slicing. And just in case bguiz didn't already know, this could also be Person* ppl[] = { &pat, &sam, &em, &sen }; - there is a slight difference in the memory management of these two options.
@Michael: Thanks, added that to my answer.
@Michael: well spotted :) raw pointer indicates that the memory is owned somewhere else.
+1 and switch checkmark to @Job : For pointing out the additional slicing problem - you've pre-empted the next thing that had me buggered!
|
3

There are two equally possible paths from an object of type StudentEmployee to be a Person.

You need to use the keyword virtual for both Student and Employee classes. See FAQ 25.8 In fact go through that entire section.

1 Comment

Thank you, that article hit the nail on the head!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.