在对象切片中,当派生类对象被复制到基类对象时,派生类的_vptr是否也像类Base?.If的其他成员一样被复制到基类的_vptr?
class Base{
public :
virtual void Display(){cout<<"In Base"<<endl;}
};
class Derived:public Base{
public:
void Display(){cout<<"In Derived"<<endl;}
};
int main()
{
Derived objD;
Base objB;
objB = objD;
objB.Display();
}对于上面的片段,我观察到了以下结果。
Output
In Base发布于 2020-07-11 19:26:50
不复制vptr。我们试着解释一下为什么。
看看您的主要功能:
Derived objD;
Base objB;
objB = objD; // <-- HERE
objB.Display();在第3行中,您将objD分配给objB。这实际上是调用Base的赋值运算符(它是自动定义的):
Base& operator=(const Base& other)并且它正在被objD作为一个基础&。所以,你的问题变成“赋值操作符复制vptr”吗?答案是“不”。默认赋值运算符仅复制类上的字段。
然后您可能会问,“为什么它不复制vptr呢?”原因是,如果复制vptr,则基类上的方法最终将使用在派生类上实现的方法。但是,总的来说,这些方法可以使用只存在于派生类(而在基类中不存在)的数据成员。因此,调用这些方法是荒谬的(在基类中逻辑上不存在数据),因此语言正确地选择不这样做。
主要问题是,当将派生类赋值给基类时,指定给它的变量只保存基类的字段,因此没有复制基类中的派生类中的字段。因此,在基类上调用派生类的方法是没有意义的。
请注意,如果要将基指针或基引用分配给派生类,则情况并非如此。在这种情况下,原始派生类实例仍然存在。它位于内存中,拥有所有的Base+Derived类字段。因此,调用该实例的派生类的方法将有权访问这些字段,因此能够调用这些方法仍然是有意义的。
这就是为什么在C++中,要执行多态性(通过虚拟方法),需要使用引用或指针。有关类似的讨论,请参见这里:Why doesn't polymorphism work without pointers/references?
发布于 2019-03-08 20:13:44
所有已知的实现都使用vptr,但细节差别很大。vptr是实现的一种方式,用于表示多态类(具有虚拟函数的类)的对象的类型,有时表示具有虚拟基类的类(非常依赖于实现)。
注意,在许多情况下,涉及多个简单继承(单个非虚拟继承)类有多个vptr。
vptr值是构造的大多数派生对象类型的函数。
对象的类型不能由用户在其生存期内更改;在构造期间,对象的类型随着其正在构建而改变;在销毁期间,它会更改回。(在构造或销毁过程中,使用不匹配对象类型的名称或其他表达式引用对象是非法的。)
您可以重用现有对象的空间来构造不同类型的对象,但它不是同一个对象:
struct X {
A a;
B b;
// requires: construction doesn't throw
};
void replace (X &x) {
x.~X();
B &b = *new (&x) B; // hope no exception here
b.f(); // use as a normal B object
x.f(); // undefined: cannot use x as a real object
X *p = &x; // legal: x isn't used as an object, only as an address
b.~B(); // clean up ressources if needed
new (&x) X; // valid: &x refers to storage, as if a void*
// x refers to a valid X object
}这样的对象重用不会改变任何现有对象的类型:replace(x)不只是作用于x (它通过销毁一个对象和重构一个对象来实现),它作用于x的存储位置。调用replace(x)后,名称x可用于引用新构造的X对象,该对象有效地识别了以前存在的X对象。
在C++中,甚至不允许对对象(保持该对象活动)的操作更改其类型。vptr无法对构造的对象进行更改。
更改声明对象的类型将破坏C++类型系统和声明对象的不变量。编译器不知道要销毁哪个类、要调用哪个虚拟函数、基类在哪里等等,这将完全改变C++的工作方式。甚至很难想象与更改现有对象的类型相关的语义。
https://stackoverflow.com/questions/55048946
复制相似问题