2

这已经是我发送的关于这个 subjet 的几篇帖子,如果这让你们中的一些人感到困扰,我深表歉意。在玩了几天并尝试了不同的替代方案(模式)之后,我得出了以下结论,这使我能够更好地提出我的问题。

我有一个向量,Base *并且有各种Derived<T>从 Base 派生的类。不同的类参数 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() 应该返回 a Derived<T> *,但它返回 a 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 *不能将 type 的对象分配给 type 的对象Derived *。因此,我不能使用*d1in function(,)

我也尝试了非虚拟接口 (NVI) 方法,但它不起作用。

有谁知道如何解决上面的简单代码,特别是最后一行?提前谢谢了。

4

2 回答 2

3

你想要什么是不可能的,因为不能保证 a 指向的对象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
}

如果要从 a 克隆Base *到 a 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它的接口(特别是一组虚拟函数,可能由派生类专门化)足以让该类的所有用户做他们想做的事需要。should 的所有用户Base都需要一个指针或引用Base(即 aBase &或 a Base *),他们不需要从Baseto 转换Derived。查找“Liskov 替换原则”以获取更多信息。

于 2015-09-09T09:59:14.117 回答
0

我认为在这种情况下你应该做铸造。您可以通过 Google 搜索更多关于 static_Cast 和 reinterpret_cast 的信息。这里有一些参考资料:如何在多态性中强制隐式转换正确的指针类型转换方法

于 2015-09-09T09:58:10.750 回答