C ++多态克隆:如何从Base指针获取Derived指针?

时间:2015-09-09 09:44:43

标签: c++ polymorphism cloning covariant-return-types

这已经是我发送过关于这个子喷气机的几篇帖子了,如果这困扰你们中的一些人,我会道歉。在玩了几天并尝试不同的替代方案(模式)之后,我得出了以下结论,这使我能够更好地阐述我的问题。

我有一个Base *的向量,并且有从Base派生的各种Derived<T>类。不同的类参数T在开头用前向声明声明。我需要的是从这个vector<Base *>中取出一对对象并使用模板应用function(Derived<T1> obj1, Derived<T2> obj2)以进行某种双重调度。但是,当我从向量中获取一个元素时,我无法将指向Base的指针转换为指向Derived的指针。因此,我无法使用function(Derived<T1> obj1, Derived<T2> obj2)

当然,这可以使用dynamic_cast<Derived<T> *>(base_ptr)简单地实现。然而,这不是我想要的,因为要做到这一点,必须事先知道T,这不是这里的情况。我必须能够从矢量中选择任何元素,而不知道他们的Derived<T>类型。

因此,我尝试了多态克隆。虽然它使用了协变返回类型,但不幸的是,它没有用。正如不同人在SO中所解释的那样,并且根据C ++标准,原因是在编译时,编译器仍然不知道对象的完整类型。因此,虽然我们希望clone()返回Derived<T> *,但它会返回Base *

接下来的几行代码表达了我的意思。 通常,多态克隆用于以下情况:

Base *b1 = new Derived;
Base *b2;
b2 = b1->clone();

这不是我想要的。我需要的是一个指向派生的指针:

Base *b1 = new Derived;
Derived *d1;
d1 = b1->clone(); // This is what I want, but it fails.

这里,编译器抱怨说类型Base *的对象不能分配给Derived *类型的对象。因此,我无法在*d1中使用function(,)

我也尝试过非虚拟接口(NVI)方法,但它没有用。

有没有人知道如何解决上面的简单代码,特别是最后一行?非常感谢提前。

2 个答案:

答案 0 :(得分:3)

您想要的是不可能的,因为无法保证Base *指向的对象实际上是Derived的实例。

您可以做的最多是为clone()函数使用协变返回类型。

class Base
{
public:
    virtual Base* clone() const
    {
        return new Base(*this);
    };
    virtual ~Base() {};
};

class Derived : public Base
{
public:
    virtual Derived* clone() const    // note different return type
                                      // this does override the inherited version
    {
        return new Derived(*this);
    }
};


int main()
{
    Base *b = new Derived;
    Derived *d1 = b->clone();    // this does not work

    Derived *o = new Derived;
    Derived *d = o->clone();    // this works
}

如果要从Base *克隆到Derived *,则需要进行运行时检查并强制进行类型转换。

Base *b = new Derived;

Base *temp = b->clone();
Derived *d = dynamic_cast<Derived *>(temp);
if (d)
{
     // d is actually an instance of Derived so can be used as such
}
else
{
     //  The cloning did not produce a Derived.  Cope with it
}
delete temp;   // this will delete the object pointed to by d, since it is the same object

然而,一般而言,您所要求的是有缺陷设计的积极指标。一般而言(假设您需要具有多态基础的类层次结构),您需要设计Base,因此其接口(特别是虚拟函数集,可能由派生类专门化)足以满足所有用户的需要。上课做他们需要的。 Base所需的所有用户都需要指向Base的指针或引用(即Base &Base *),并且不需要他们从Base投射{1}}到Derived。查看“利斯科夫替代原则”以获取更多信息。

答案 1 :(得分:0)

我认为在这种情况下你应该进行施法。你可以谷歌更多关于static_Cast和reinterpret_cast。以下是一些参考文献:How to force implicit conversion in polymorphismProper way of casting pointer types