试图解决问题(实际上是在Ada中)我想出了以下代码。为什么合法?
class Superclass {
public:
virtual void Announce() {
printf("I am the superclass\n");
}
};
class Subclass : public Superclass {
public:
void Announce() {
printf("I am the subclass\n");
}
};
int main() {
Superclass osuper;
Subclass osub;
Superclass* p = &osub;
*p = osuper;
osub.Announce();
return 0;
}
在main()
中,我创建了Subclass
的实例,然后使用Superclass
的实例对其进行物理覆盖。然后,我成功地在覆盖(以及如此损坏的)对象上调用了Subclass
的方法。
我无法直接指定osub = osuper
,因为这没有任何意义,但通过指针我似乎绕过了它。上面的代码编译得很好,没有任何警告,但是当我调用osub.Announce()
时,osub
内的内存不再包含有效的Subclass
对象。
这可能是类型安全的(甚至,通常是安全的),但编译器似乎非常高兴。为什么呢?
答案 0 :(得分:6)
在对象上使用=运算符无效,并且它不会覆盖任何内容,将使用默认的复制构造函数。 如果你想真正覆盖内存中的对象,请尝试memcpy(p,& osub,sizeof(Superclass))。现在这将是一个覆盖:)
答案 1 :(得分:2)
您正在调用复制赋值运算符,而不是“物理覆盖”。这个函数与构造函数之外的任何其他函数一样,可以修改已经存在的对象的成员,它不是“魔法”。
您的对象没有成员变量,因此隐式生成的operator=
调用是无操作。没有“腐败的对象”。 osub.Announce();
致电Subclass::Announce
,因为osub
是Subclass
。
调用的实际函数是Superclass::operator=(Superclass const &);
。
函数Subclass::operator=(Subclass const &);
在重载决策中失败,因为osuper
不会隐式转换为Subclass const &
。
你可能会得到的是,如果Subclass有成员变量,那么行*p = osuper;
可能会使osub
对象处于Subclass
设计者不想要的状态。
答案 2 :(得分:1)
需要很奇怪。 当调用子类实例的构造函数时,超类的构造函数将被调用到init成员变量。 但是,如果你想要这个,你可以实现这样的成员函数:
Subclass& copy(const Superclass& superobject);
答案 3 :(得分:0)
您应该在子类中放置一个返回超类的方法。 SuperClass getSuperClass(){ SuperClass sup; //复制内容; 返回; }
答案 4 :(得分:0)
这个工作原理的执行摘要似乎是:隐式复制构造函数讨厌你,并想伤害你。
隐式复制构造函数看起来像,就像它执行对象的逐字节复制一样,从而使得assign-to对象与assign-from对象相同。但是,它并没有这样做。它只是复制成员。它特别不会复制对象的vtable指针。分配可能会遇到同样的问题(虽然我还没有检查过这个问题)。我对C ++ 11的移动一无所知。
如果这违反了您的任何一个级别的合同,或者以任何其他方式对您的类层次结构没有任何意义,那么它基本上很难成为您。
这个故事的寓意是:课程应该始终从boost::noncopyable
继承。
(我知道复制构造函数是从C开始的。这不是一个借口。)