Tullie Murrell
Tullie Murrell

Reputation: 47

Issues with virtual function

I have a class Student which inherits from Person. Both classes just have the defined virtual function printDetails() and their constructors.

Person student = Student("John Smith", "a1234567");
student.printDetails();

When i have the code above in my main the printDetails() function is called in the Person class.

Person* student = new Student("John Smith", "a1234567")
student->printDetails()

However when i have the dynamically allocated version above the function is called by the student.

My question is, why is printDetails() being called in the Person class rather then in the Student one for the first segment of code?

Upvotes: 3

Views: 197

Answers (3)

SysAdmin
SysAdmin

Reputation: 5585

To understand the problem, you must know how the objects Person and Student is Laid out in memory.

Consider the classes

class Person
{
protected:
    int age;

public:
    Person(int a)
    {
        age = a;
    }
    virtual void Print()
    {
        cout<<"Person Age : "<<age;
    }
};

class Student : public Person 
{
    int Id;

public:
    Student(int id, int age)
        :Person(age)
    {
        Id = id;
    }
    virtual void Print()
    {
        cout<<"Student Age : "<<age<<" Id : "<<Id;
    }
};

Following is the object layout Person and Student objects

-----------------------------------------------------
|_Virtual_Table_Ptr_Person | Data members of Person |
-----------------------------------------------------
-------------------------------------------------------------------------------
|_Virtual_Table_Ptr_Student | Data members of Person | Data Members of Student|
-------------------------------------------------------------------------------

So, For the statement Person student = Student() , The memory of temp object Student() gets copied over to the memory address of student. So the object gets sliced here. The _Vptr however remains the same (i.e VT of Person).

Upvotes: 0

David Hammen
David Hammen

Reputation: 33126

Person student = Student("John Smith", "a1234567");

Your student isn't a Student. It is a Person. You declared it as such. So of course the function that is called is Person::printDetails.

What's happening is called "slicing". See this FAQ for details: What is object slicing? .

Update
This answers roybatty's question "Why does the second case call Student::printDetails?"

The first case loses all details that the object is a Student. That's just what happens when one assigns a child class to a parent class. The parent class object doesn't know of the member data that the child class adds, or of the functions that the child class overrides. How can it?

That's not the case in the second case. Here it's a pointer that is being upcast to a parent class pointer. There's still a Student object that is intimately connected to the Parent* pointer, even though that pointer is a base class pointer. There would be no point in declaring a member function virtual if that connection to the derived class didn't exist.

Upvotes: 7

Mark Ransom
Mark Ransom

Reputation: 308520

You're a victim of what's called object slicing. The object student is of type Person, but it was created with the copy constructor of Person applied to a Student object. Slicing means that all the extra attributes of being a Student are lost.

Upvotes: 1

Related Questions