复制实例化派生类的类的构造函数

Copy Constructors of classes instantiating derived classes

提问人:Paul 提问时间:2/17/2022 更新时间:2/17/2022 访问量:60

问:

我一直在尝试创建一个实例化派生类的类的复制构造函数,但没有成功。

假设我有以下纯虚拟类:

class AbstractBar{
public:
    virtual void printMe() = 0;

};

类继承自如下:BarAbstractBar

class Bar: public AbstractBar {
    std::string name_;

public:
    explicit Bar(std::string name) : name_ {std::move(name)}{};

    void printMe() override { std::cout << name_ << std::endl; }
};

我的类现在尝试通过声明指向类型的指针来利用多态性,如下所示:FooAbstractClass

class Foo{
    std::unique_ptr<AbstractBar> theBar_;

public:
    explicit Foo(std::unique_ptr<Bar> bar){
        theBar_ = std::move(bar);
    };

    void printBar(){
        theBar_->printMe();
    }
};

但是,我确实想被复制,所以我添加了以下复制构造函数:Foo

    Foo(const Foo &other) {
        theBar_ = std::unique_ptr<AbstractBar>();
        *theBar_ = *(other.theBar_);
    }

这就是它打破的地方。

我收集到的是这可能是一个问题,因为在复制构造函数中认为它指向一个,但是当我尝试复制它指向的对象时,在下一行中,我实际上给了它一个派生类。theBarAbstractBarBar

有没有正确的方法来实现这个复制构造函数?

C++ 指针复制 构造函数

评论

1赞 MatG 2/17/2022
std::unique_ptr无法复制,只是移动
3赞 WhozCraig 2/17/2022
我怀疑一个协变克隆即将出现在菜单上。
0赞 Paul 2/17/2022
@MatG那么,我假设创建一个新的对象,然后尝试复制前一个指向的对象,从而构成 s 领域的 a?我想,同样正确的是,永远不可能创建包含其定义中任何位置的对象的副本,即现在有办法按原样实现此复制构造函数。unique_ptrcopyunique_ptrunique_ptr
0赞 Gabeeka 2/17/2022
如果你想让你的 Foo 类成为语义上正确的可复制类,我建议使用 std::shared_ptr 而不是 std:unique_ptr。由您决定是否允许复制 Foo 有意义,如果有意义,则使用共享指针。

答:

3赞 WhozCraig 2/17/2022 #1

首先,确实是独一无二的。因此,你不能指望两件事通过复制它们来指向同一个实例。也就是说,我认为您要做的是克隆该成员持有的任何“东西”,unique_ptr允许深度复制 .std::unique_ptr<T>Foo

如果是这种情况,则需要协变克隆。见下文:

#include <iostream>
#include <string>
#include <memory>

struct AbstractBar
{
    virtual ~AbstractBar() = default;

    virtual std::unique_ptr<AbstractBar> clone() = 0;
    virtual void printMe() = 0;
};

class Bar : public AbstractBar
{
    std::string name_;

public:
    explicit Bar(std::string name) : name_{std::move(name)} {};

    std::unique_ptr<AbstractBar> clone() override
    {
        return std::make_unique<Bar>(name_);
    }

    void printMe() override
    {
        std::cout << name_ << std::endl;
    }
};

class Foo
{
    std::unique_ptr<AbstractBar> theBar_;

public:
    explicit Foo(std::unique_ptr<Bar> bar)
        : theBar_(std::move(bar))
    {
    }

    Foo(const Foo &other)
        : theBar_(other.theBar_->clone())
    {
    }

    void printBar()
    {
        theBar_->printMe();
    }
};

int main()
{
    Foo foo(std::make_unique<Bar>("Some String"));
    Foo bar(foo);

    foo.printBar();
    bar.printBar();
}

重要提示:并且每个实例都通过指向 的抽象基的唯一指针,即 。希望这就是本意。这不是唯一的方法,但它可能是最容易理解的。foobarBarBarAbstractBar

评论

0赞 Gabeeka 2/17/2022
这个解决方案伤害了我的眼睛,很多。为什么语义上很难正确?在这里,你假装复制是不允许的,但有一个黑客来“破坏该合同”。我认为这样做的正确方法是使用共享指针而不是唯一指针。
4赞 StoryTeller - Unslander Monica 2/17/2022
@Gabeeka - 不复制,OP 确实想复制。只有当指针确实可以共享时,引入共享所有权才是“正确的方式”。OP没有对此作出任何说明。shared_ptr