C++ 虚拟方法 return 不同的派生类型

C++ Virtual Method return different derived types

参考这个问题:C++ virtual function return type

让我们考虑以下一组对象。

class ReturnTypeBase
{
};

class ReturnTypeDerived1 : public ReturnTypeBase
{
public:
    int x;
};

class ReturnTypeDerived2 : public ReturnTypeBase
{
public:
    float y;
};

class Base
{
public:
    virtual ReturnTypeBase* Get() = 0;
};

class Derived1: public Base
{
public:
    virtual ReturnTypeDerived1* Get()
    {
        return new ReturnTypeDerived1();
    }
};

class Derived2: public Base
{
public:
    virtual ReturnTypeDerived2* Get()
    {
        return new ReturnTypeDerived2();
    }
};

这些对象可以按以下方式使用吗?

Base* objects[2];

objects[0] = new Derived1();

objects[1] = new Derived2();

ReturnTypeDerived1* one = objects[0]->Get();

ReturnTypeDerived2* two = objects[1]->Get();

我假设因为 return 类型是协变的(?),上面的对象集是合法的 C++。是否会调用适当的 Get() 方法?指针 one/two 是否可以在不强制转换的情况下分配给 Get() 方法的 return 值?

代码将不会像编写的那样编译。因为 objects[0] 具有静态类型 Base*,调用 Get 函数会导致返回具有静态类型 ReturnTypeBase* 的指针。由于这是一个重写的虚函数,派生的 class 的 Get 函数将如您所愿地被调用,并且返回的指针实际上指向一个 ReturnTypeDerived1 对象,但是编译器无法证明这一点。你需要演员表:

auto one = static_cast<ReturnTypeDerived1*>(objects[0]->Get());
auto two = static_cast<ReturnTypeDerived2*>(objects[1]->Get());

如果您将 ReturnTypeBase 设为多态类型,您可以在此处使用 dynamic_cast 来避免在动态类型错误时出现未定义的行为。

如前所述,您将在 .Get() 调用中遇到编译器错误。 如果你想避免这种情况,请分配给 base class..

ReturnTypeBase * one = objects[0].Get();
ReturnTypeBase * two = objects[1].Get();

只要您通过基class中定义的抽象方法(例如'toString()'方法)访问'one'和'two',您就不会内部数据有问题。

如果您打算在基础 class 的所有实例中对数据进行相同处理,您可能需要考虑改用模板 class。