我有一个继承自Person的班级学生。 这两个类只有定义的虚函数printDetails()及其构造函数。
Person student = Student("John Smith", "a1234567");
student.printDetails();
当我在main中使用上面的代码时,在Person类中调用printDetails()函数。
Person* student = new Student("John Smith", "a1234567")
student->printDetails()
但是当我有动态分配的版本时,学生会调用该函数。
我的问题是,为什么在Person类中调用printDetails()而不是在第一段代码的Student 1中调用它?
答案 0 :(得分:7)
Person student = Student("John Smith", "a1234567");
您的student
不是Student
。这是Person
。你宣布它是这样的。当然,调用的函数是Person::printDetails
。
发生的事情被称为“切片”。有关详细信息,请参阅此常见问题解答:What is object slicing?。
<强>更新强>
这回答了roybatty的问题“为什么第二个案例会调用Student::printDetails
?”
第一种情况失去了对象为Student
的所有细节。这就是当一个子类分配给父类时会发生什么。父类对象不知道子类添加的成员数据,也不知道子类重写的函数。它怎么样?
第二种情况并非如此。这是一个指向父类指针的指针。仍有一个Student
对象与Parent*
指针紧密相连,即使该指针是基类指针。如果与派生类的连接不存在,则声明成员函数virtual是没有意义的。
答案 1 :(得分:1)
你是所谓的对象切片的受害者。对象student
的类型为Person
,但它是使用应用于Person
对象的Student
的复制构造函数创建的。切片意味着失去Student
的所有额外属性。
答案 2 :(得分:0)
要理解这个问题,你必须知道对象Person和Student是如何在内存中放置的。
考虑课程
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;
}
};
以下是对象布局Person和Student对象
-----------------------------------------------------
|_Virtual_Table_Ptr_Person | Data members of Person |
-----------------------------------------------------
-------------------------------------------------------------------------------
|_Virtual_Table_Ptr_Student | Data members of Person | Data Members of Student|
-------------------------------------------------------------------------------
因此,对于语句 Person student = Student(),临时对象 Student()的内存被复制到 student <的内存地址/ em>的。所以对象在这里切成薄片。然而_Vptr仍然是相同的(即人的VT)。