从函数返回的std :: unique_ptr中的抽象类不起作用

问题描述

class Base{
public:
    virtual std::string typeName() = 0;
    virtual ~Base() = 0;
};
Base::~Base(){}

class D1 : public Base{
public:
    std::string typeName();
    std::vector<std::unique_ptr<Base>> children;
    ~D1(){};
};
class D2 : public Base{
public:
    std::string typeName();
    std::unique_ptr<Base> child;
    ~D2(){};
};
std::string D1::typeName(){
    return "class D1";
}
std::string D2::typeName(){
    return "class D2";   
}

class Program{
public:
   std::unique_ptr<Base> D1Generic();
   std::unique_ptr<Base> D2Generic();
};
std::unique_ptr<Base> Program::D1Generic(){
    return std::make_unique<Base>(D1{});
}
std::unique_ptr<Base> Program::D2Generic(){
    return std::make_unique<Base>(D2{});
}

代码只是简化版本,可复制我面临的问题。 我的设计意图是在一棵树上创建访客模式,然后将其变成另一棵树。

我将紧迫的问题缩小为D1GenericD2Generic函数。我的目的是创建一个可扩展的接口,该接口允许Base的多个子类适合作为多态的唯一指针变量。

我遇到了这些错误

/usr/bin/../lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/c++/7.5.0/bits/unique_ptr.h:821:34: error: 
      allocating an object of abstract class type 'Base'
    { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
                                 ^
main.cpp:38:17: note: in instantiation of function template specialization
      'std::make_unique<Base,D1>' requested here
    return std::make_unique<Base>(D1{});
                ^
main.cpp:8:25: note: unimplemented pure virtual method 'typeName' in 'Base'
    virtual std::string typeName() = 0;
                        ^
main.cpp:9:13: note: unimplemented pure virtual method '~Base' in 'Base'
    virtual ~Base() = 0;
            ^
In file included from main.cpp:4:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/c++/7.5.0/memory:80:
/usr/bin/../lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/c++/7.5.0/bits/unique_ptr.h:821:34: error: 
      allocating an object of abstract class type 'Base'
    { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
                                 ^
main.cpp:41:17: note: in instantiation of function template specialization
      'std::make_unique<Base,D2>' requested here
    return std::make_unique<Base>(D2{});
                ^
2 errors generated.

解决方法

尝试一下:

std::unique_ptr<Base> Program::D1Generic() {
    return (std::unique_ptr<Base>)new D1();
}
std::unique_ptr<Base> Program::D2Generic() {
    return (std::unique_ptr<Base>)new D2();
}
,

Abstract class and unique pointer中探讨了基本问题,但是解决方案的详细信息有所不同。

std::make_unique<T>的调用会动态分配类型T的对象。参数不影响创建的内容,仅影响如何初始化。当您提供类型为D1的对象以初始化类型为Base的动态分配对象时,对D1对象的引用将转换为对其Base子对象的引用-object,然后从中复制构造新对象。

您(大概)想做的是动态分配类型为D1的对象,然后将其地址转换为指向Base的指针。也就是说,在构造后

return std::make_unique<D1>();

这将动态分配类型为D1的对象,从而为新对象创建一个unique_ptr。该智能指针是通过move语义返回的。这意味着返回的对象(声明为unique_ptr<Base>)是由unique_ptr<D1>返回的make_unique进行移动构造的。幸运的是,这是允许的!