1

我有点惊讶以下代码没有按预期工作:

#include "stdio.h"

class RetA
{
public:
    virtual void PrintMe () { printf ("Return class A\n"); }
};

class A
{
public:
    virtual RetA GetValue () { return RetA (); }
};

class RetB : public RetA
{
public:
    virtual void PrintMe () { printf ("Return class B\n"); }
};

class B : public A
{
public:
    virtual RetA GetValue () { return RetB (); }
};

int main (int argc, char *argv[])
{
    A instance_A;
    B instance_B;
    RetA ret;

    printf ("Test instance A: ");
    ret = instance_A.GetValue ();
    ret.PrintMe (); // Expected result: "Return class A"

    printf ("Test instance B: ");
    ret = instance_B.GetValue ();
    ret.PrintMe (); // Expected result: "Return class B"

    return 0;
}

那么,虚拟方法在返回值时不起作用吗?我应该恢复在堆上分配返回类,还是有更好的方法?

(实际上我想这样做是为了让一些从容器类继承的不同类根据类返回不同的迭代器类实例......)

4

5 回答 5

17

多态行为不能按值起作用,您需要返回指针或引用才能使其起作用。

如果按值返回,则会得到所谓的“切片”,这意味着只有对象的父部分被返回,因此您已经成功地将子对象分割成父对象,这根本不安全。

看一看: 什么是对象切片?

于 2009-08-10T09:18:49.913 回答
0

做动态重载,你需要让静态类型与动态类型不同。你不在这里。返回引用或指针(并注意实时时间)而不是值。

于 2009-08-10T09:15:12.043 回答
0

虚拟适用于类型的指针或引用声明,因此更改您的代码:virtual RetA& GetValue () 或 virtual RetA* GetValue (),但您发布的不是虚拟的 - 您使用“复制语义”。

于 2009-08-10T09:18:22.490 回答
0

你必须返回指针或地址

virtual RetA GetValue () { return RetB (); }

如果没有,您从 GetValue 得到的是 RetA 而不是 RetB。

于 2009-08-10T09:21:53.387 回答
0

除了已经提到的“切片”问题,PrintMe 方法也必须是虚拟的。

struct B 
{
   void print1() const { std::cout << "B" << std::endl; }
   virtual void print2() const { print1(); }
};
struct D : public B
{
   void print1() const { std::cout << "D" << std::endl; }
   virtual void print2() const { print1(); }
};
B& f() 
{
   static D d;
   return d; // the object returned is in fact a D, not a B
}
int main(){
   f().print1(); // B: calling a non-virtual method from a B reference
   f().print2(); // D: the method is virtual will exec B::print2
}
于 2009-08-10T15:03:10.330 回答