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

发布于 2024-12-09 23:39:11 字数 2106 浏览 1 评论 0原文

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

有一个 Base 类和两个子类:Child1Child2。我需要基于 Child1 创建一个 Child2 类型的对象,即。最重要的是,我需要将 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

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

编辑:此处询问后续

I need to copy-construct an object simultaneously changing it's type to another class being a member of the same class-hierarchy. I've read about polymorphic copy-constructors and (hopefully) understand the idea behind it. Yet, I still don't know if this pattern applies to my case and, if so, how to implement it. I think it's best if I show what I need on an example.

There is a Base class and two child classes, Child1 and Child2. I need to create an object of type Child2 basing on Child1, ie. most of all, I need to copy the object p_int is pointing to from Child1 to Child2. I've written a simple program to illustrate it:

#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();
}

Unfortunately, the outcome is as below, ie. there is no type conversion:

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

What exactly do I need to implement, to be able to achieve what I need? I'm starting to think there is a type-conversion mechanism I need to implement rather than a polymorphic copy-constructor, but I'm confused already.

EDIT: Asked a follow up here

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

雪落纷纷 2024-12-16 23:39:11

最简单的解决方案可能是实现一个以 Child1& 作为参数的 Child2 构造函数。然后你可以简单地调用:

Child2* c2 = new Child2(*c1);

Simplest solution would probably be to implement a Child2 constructor taking a Child1& as parameter. Then you could simply call:

Child2* c2 = new Child2(*c1);
一梦浮鱼 2024-12-16 23:39:11

如果您只有 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); 

If you only have 2 child classes, then the easiest way is to create a conversion constructor:

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

c2 = new Child2(*c1); 

If you have several Child classes, and you need to create a Child2 from any of them, then you could do something like this:

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); 
戏蝶舞 2024-12-16 23:39:11
c2 = (Child2*)c1->clone();

这是一个严重的错误,而 c 风格的转换隐藏了该错误。

如果您使用C++风格的强制转换,那么它不会隐藏该错误,并且您会知道它。在本例中,C++ 风格的转换为:dynamic_cast。用它来自己发现错误。

从代码中可以清楚地看出,c1-clone() 创建了 c1 的克隆,其类型为 Child1*clone( ) 返回一个 Base* 类型的指针(从 Child1* 向上转换之后),您尝试向下转换为 Child2*< /代码>。如果您使用正确的转换:dynamic_cast,则转换应该失败。

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

Here is a serious bug, and the c-style cast hides the bug.

If you use C++-style cast, then it will not hide the bug, and you will know it. In this case, the C++-style cast is : dynamic_cast. Use it to discover the bug yourself.

As it is clear from the code thatc1-clone() creates a clone of c1 whose type is Child1* and clone() returns a pointer of type Base* (after upcasting from Child1*), which you're trying to down-cast to Child2*. The cast should fail if you use proper cast : dynamic_cast.

红ご颜醉 2024-12-16 23:39:11

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

The clone() patterns allows you to create a valid copy/clone of the object of a child class having just the base reference, e.g. in your case it allows you to do the following:

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

What you could need is a "copy-constructor" that allows you to copy from a base class, e.g.:

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();
}

Result:

Child1: 7275360:4 0
Child2: 7340936:4 1
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文