以下代码:
#include <stdio.h>
class Parent
{
public:
virtual void func() {printf("Parent\n");}
};
class Child1 : public Parent
{
virtual void func() {printf("Child1\n");}
};
class Child2 : public Parent
{
virtual void func() {printf("Child2\n");}
};
int main(int argc, char* argv[])
{
Parent & obj = Child1();
obj.func();
obj = Child2();
obj.func();
return 0;
}
产生以下结果:
expected: Child1 Child2.
actual: Child1 Child1.
(在VS2010上编译)
我猜vptr不会被赋值改变。它有一种方法可以重新创建它(除了使用指向Parent的指针并使用new分配它)?
感谢
答案 0 :(得分:3)
您正在调用obj上的默认赋值运算符,该运算符仍然是Child1类型,其参数类型为Child2。对象本身仍然是Child1
类型。您可以通过在所有3个类上实现operator =
并在那里插入print语句来验证这一点。
答案 1 :(得分:1)
无法重新引用引用 - 它们在整个生命周期中引用相同的对象。如果你想要一些可以改变它引用的对象的东西,那么你需要使用[智能]指针而不是引用。
您在此处执行的操作是slicing Child2
的实例,方法是将其分配给Child1
的实例。
答案 2 :(得分:1)
Parent & obj = Child1();
您创建对Child1
类型对象的引用。这就像说
Child1 c1;
Parent& obj = c1;
obj
现在只是c1
的另一个名称,它是Child1
类型的对象。
obj = Child2();
obj.func();
现在,这就像说
c1 = Child2();
c1.func();
所以你看,你仍然在func
类型的对象上调用Child1
。
答案 3 :(得分:1)
C ++中的两个基本属性:一个对象,一旦创建,永远不会 更改其类型,引用一旦初始化,始终引用 同一个对象。
这里发生的是你正在调用提供的编译器
operator=
的非虚拟Parent
,几乎肯定不是什么
你自找的。但更一般地说,赋值和继承不是
一起工作(正是因为你不能改变一个类型
宾语);大多数时候,在使用继承时,你应该禁止
赋值(例如,从boost::noncopyable
继承)。它的
可以使用。实现多态类的值语义
字母/信封成语,但这是一个沉重的解决方案,很少
适当。
(我可能会补充一点,你的代码不能用C ++编译器编译。你是 使用临时初始化对非const的引用,而不是 合法的C ++。允许这是Microsoft扩展。)
答案 4 :(得分:0)
您正在做的事情应该在编译时出错。您不能将临时变量(由Child2()
创建)分配给引用变量。您必须在Child2
之前创建一个实例,并将该变量分配给崇敬者。