1

以下代码:

#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 分配给它)?

谢谢

4

5 回答 5

3

您正在调用 obj 上的默认赋值运算符,它仍然是 Child1 类型,带有 Child2 类型的参数。对象本身仍然是 type Child1。您可以通过operator =在所有 3 个类上实现并在其中插入打印语句来验证这一点。

于 2011-11-22T10:26:20.853 回答
1

引用不能被重新定位——它们在整个生命周期中都引用同一个对象。如果您想要一些可以更改它所引用的对象的东西,那么您需要使用 [智能] 指针而不是引用。

您在这里所做是通过将实例Child2分配给Child1.

于 2011-11-22T10:29:50.520 回答
1
Parent & obj = Child1();

您创建对类型对象的引用Child1。这就像说

Child1 c1;
Parent& obj = c1;

obj现在只是一个不同的名称c1,它是一个类型的对象Child1

obj = Child2();
obj.func();

现在,这就像说

c1 = Child2();
c1.func();

所以你看,你仍然在调用functype 的对象Child1

于 2011-11-22T10:30:09.197 回答
1

C++ 中的两个基本属性:一个对象,一旦创建,就永远不会改变它的类型,而一个引用,一旦被初始化,总是指向同一个对象。

这里发生的情况是您正在调用为 提供的非虚拟编译器operator=Parent这几乎肯定不是您想要的。然而,更一般地说,赋值和继承不能很好地协同工作(正是因为你不能改变对象的类型);大多数时候,在使用继承时,您应该禁止赋值(boost::noncopyable例如,通过从 继承)。可以使用字母/信封惯用语为多态类实现值语义,但这是一个繁重的解决方案,而且很少适用。

(我可能会补充一点,您的代码不能使用 C++ 编译器进行编译。您正在使用临时初始化对非常量的引用,这不是合法的 C++。允许这是 Microsoft 扩展。)

于 2011-11-22T10:34:14.390 回答
0

您所做的应该会在编译时出错。您不能将临时变量(由 创建Child2())分配给引用变量。您必须在 of 之前创建一个实例Child2,并将该变量分配给尊敬。

于 2011-11-22T10:30:23.257 回答