首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >虚拟表和对象切片

虚拟表和对象切片
EN

Stack Overflow用户
提问于 2019-03-07 16:47:36
回答 2查看 465关注 0票数 1

在对象切片中,当派生类对象被复制到基类对象时,派生类的_vptr是否也像类Base?.If的其他成员一样被复制到基类的_vptr?

代码语言:javascript
复制
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();
}

对于上面的片段,我观察到了以下结果。

代码语言:javascript
复制
Output
In Base
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-07-11 19:26:50

不复制vptr。我们试着解释一下为什么。

看看您的主要功能:

代码语言:javascript
复制
Derived objD;
Base objB;
objB = objD;  // <-- HERE
objB.Display();

在第3行中,您将objD分配给objB。这实际上是调用Base的赋值运算符(它是自动定义的):

代码语言:javascript
复制
Base& operator=(const Base& other)

并且它正在被objD作为一个基础&。所以,你的问题变成“赋值操作符复制vptr”吗?答案是“不”。默认赋值运算符仅复制类上的字段。

然后您可能会问,“为什么它不复制vptr呢?”原因是,如果复制vptr,则基类上的方法最终将使用在派生类上实现的方法。但是,总的来说,这些方法可以使用只存在于派生类(而在基类中不存在)的数据成员。因此,调用这些方法是荒谬的(在基类中逻辑上不存在数据),因此语言正确地选择不这样做。

主要问题是,当将派生类赋值给基类时,指定给它的变量只保存基类的字段,因此没有复制基类中的派生类中的字段。因此,在基类上调用派生类的方法是没有意义的。

请注意,如果要将基指针或基引用分配给派生类,则情况并非如此。在这种情况下,原始派生类实例仍然存在。它位于内存中,拥有所有的Base+Derived类字段。因此,调用该实例的派生类的方法将有权访问这些字段,因此能够调用这些方法仍然是有意义的。

这就是为什么在C++中,要执行多态性(通过虚拟方法),需要使用引用或指针。有关类似的讨论,请参见这里:Why doesn't polymorphism work without pointers/references?

票数 3
EN

Stack Overflow用户

发布于 2019-03-08 20:13:44

所有已知的实现都使用vptr,但细节差别很大。vptr是实现的一种方式,用于表示多态类(具有虚拟函数的类)的对象的类型,有时表示具有虚拟基类的类(非常依赖于实现)。

注意,在许多情况下,涉及多个简单继承(单个非虚拟继承)类有多个vptr。

vptr值是构造的大多数派生对象类型的函数。

对象的类型不能由用户在其生存期内更改;在构造期间,对象的类型随着其正在构建而改变;在销毁期间,它会更改回。(在构造或销毁过程中,使用不匹配对象类型的名称或其他表达式引用对象是非法的。)

您可以重用现有对象的空间来构造不同类型的对象,但它不是同一个对象:

代码语言:javascript
复制
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++的工作方式。甚至很难想象与更改现有对象的类型相关的语义。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55048946

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档