views:

90

answers:

2

Hi,

(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:
http://stackoverflow.com/questions/2423231/polymorphism-relates-inheritance
http://stackoverflow.com/questions/1889996/inheritance-mucking-up-polymorphism-in-c

+3  A: 

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.

dirkgently
@dirkgently : Thank you, that article hit the nail on the head!
bguiz
+5  A: 

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};
Job
But, obviously, calling new like that will almost certainly lead to a memory leak
Falmarri
+1 for the slicing. And just in case bguiz didn't already know, this could also be Person* ppl[] = { - there is a slight difference in the memory management of these two options.
Michael
@Falmarri: Why? You still have the array of pointers.
Job
@Michael: Thanks, added that to my answer.
Job
@Michael: well spotted :) raw pointer indicates that the memory is owned somewhere else.
Matthieu M.
+1 and switch checkmark to @Job : For pointing out the additional slicing problem - you've pre-empted the next thing that had me buggered!
bguiz
@Job: I just mention that because the OP is clearly not too familiar with C++ and manually managing memory in a pointer array can be confusing. I probably worded it too harshly.
Falmarri
@bguiz- this talk about memory is to indicate that at the end of the application you'll want to remember to `for (int i = 0; i < (sizeof(ppl)/sizeof(ppl[0])); ++i) delete ppl[i];`
dash-tom-bang