具有类型转换的多态复制构造函数

时间:2011-10-14 08:54:45

标签: c++ polymorphism type-conversion polymorphic-associations

我需要复制构造一个对象,同时将它的类型更改为另一个类,该类是同一个类层次结构的成员。我已经阅读过多态复制构造函数,并且(希望)理解它背后的想法。然而,我仍然不知道这种模式是否适用于我的情况,如果适用,如何实施它。我认为最好是在一个例子中展示我需要的东西。

有一个Base课程和两个子课程,Child1Child2。我需要基于Child2创建一个Child1类型的对象,即。最重要的是,我需要将p_int指向的对象从Child1复制到Child2。我写了一个简单的程序来说明它:

#include <iostream>
using namespace std;

class Base {
public:
    Base() { p_int = new int; *p_int = 0; }
    ~Base() { delete p_int; }
    virtual Base* clone() const = 0;

    void setpInt(int val) { *p_int = val; }
    void setInt(int val) { a = val; }
    virtual void print() {
        cout << "Base: ";
        cout << (long)p_int << ":" << *p_int << " " << a << endl;
    }
protected:
    int* p_int;
    int a;
};

class Child1 : public Base {
public:
    Child1() {};
    Child1(const Child1& child) {
        p_int = new int (*child.p_int);
        a = child.a + 1;
    }

    Base* clone() const { return new Child1(*this); }

    void print() {
        cout << "Child1: ";
        cout << (long)p_int << ":" << *p_int << " " << a << endl;
    }
};

class Child2 : public Base {
public:
    Child2() {};
    Child2(const Child2& child) {
        p_int = new int (*child.p_int);
        a = child.a + 1;
    }

    Base* clone() const { return new Child2(*this); }

    void print() {
        cout << "Child2: ";
        cout << (long)p_int << ":" << *p_int << " " << a << endl;
    }
};

int main() {
    Child1* c1 = new Child1();
    Child2* c2;

    c1->setpInt(4);
    c1->print();

    c2 = (Child2*)c1->clone();
    c2->print();
}

不幸的是,结果如下,即。没有类型转换:

Child1: 162611224:4 0
Child1: 162611272:4 1

我需要实现什么才能实现我的需求?我开始认为我需要实现一种类型转换机制而不是多态复制构造函数,但我已经很困惑了。

编辑:提出跟进here

4 个答案:

答案 0 :(得分:5)

最简单的解决方案可能是以Child2为参数实现Child1&构造函数。然后你可以简单地打电话:

Child2* c2 = new Child2(*c1);

答案 1 :(得分:4)

如果您只有2个子类,那么最简单的方法是创建转换构造函数:

class Child2: public Base
{
public: 
    Child2(Child1 const& child)
    {
            p_int = new int (*child.p_int);
            a = child.a + 1;        
    }
}; 

c2 = new Child2(*c1); 

如果您有多个Child类,并且需要从其中任何一个创建Child2,那么您可以执行以下操作:

class Base
{
public: 
    void CopyFrom(Base* base)
    {
            p_int = new int (*base.p_int);
            a = base.a + 1;     
    }
}; 

class ChildX: public Base
{
public: 
    static ChildX* CreateFrom(Base* base)
    {
        ChildX ch = new ChildX(); 
        ch->CopyFrom(base); 
        return ch; 
    }
}; 

c2 = Child2::CreateFrom(c1); 

答案 2 :(得分:2)

c2 = (Child2*)c1->clone();

这是一个严重的错误,而c-style演员隐藏错误。

如果你使用C ++风格的强制转换,那么它不会隐藏错误,你就会知道它。在这种情况下,C ++风格的强制转换是:dynamic_cast。用它来自己发现bug。

从代码中可以清楚地看出,c1-clone()创建了c1的克隆,其类型为Child1*clone()返回类型为Base*的指针(在从Child1*向上转播之后,你试图向下转换为Child2*。如果你使用适当的演员阵容,演员阵容应该失败:dynamic_cast

答案 3 :(得分:2)

clone()模式允许您创建仅具有基本引用的子类对象的有效副本/克隆,例如在您的情况下,它允许您执行以下操作:

Base* basePtr = getBaseOrSomeDerivedObject();
Base* copy = basePtr.clone(); // Create a copy that is an object of an actual basePtr's type.

您可能需要的是一个“复制构造函数”,它允许您从基类复制,例如:

class Base {
public:
    // [...]    
    Base(const Base& other) : a(other.a + 1)
    {
        p_int = new int(*(other.p_int));
    }
    // [...]
};


class Child2 : public Base {
public:
    // [...]
    Child2(const Base& base) : Base(base) {}
    // [...]
};

int main() {
    // [...]
    c2 = new Child2(*c1);
    c2->print();
}

结果:

Child1: 7275360:4 0
Child2: 7340936:4 1