首页 > 解决方案 > unique_ptr 的自定义克隆不返回正确的类型

问题描述

我有这两个类:

class Operation {
    public:
        virtual std::unique_ptr<Operation> clone() = 0;
};

class Plus : public Operation {
    public:
        std::unique_ptr<Operation> clone() override {
            return std::make_unique<Plus>(*this);
        };
};

我有这个函数,它检查函数的类型:

template<typename Base, typename T>
inline bool instanceof(const T*) {
   return std::is_base_of<Base, T>::value;
}

我的克隆方法遇到问题,在我克隆对象后它没有通过我的实例。

std::unique_ptr<SweCpp::Upn::classesforOp::Plus> p1 = std::make_unique<SweCpp::Upn::classesforOp::Plus>();
auto p2 = p1->clone();

if(!instanceof<SweCpp::Upn::classesforOp::Plus>(p2.get())) return false;
return true;

此检查失败,因为我返回了一般类型,unique_ptr<Operation>而不是unique_ptr<Plus>在我的克隆方法中。如何更改我的克隆,使其返回子类,而不是我的接口类Operation

标签: c++unique-ptr

解决方案


您的模板参数是向后的。您设置BasePlus,并T推断为Operation。因此,您调用std::is_base_of<Plus, Operation>::value的总是错误的,因为Plus它不是Operation. 反之亦然,Operation是基数Plus。所以交换模板参数:

template<typename T, typename Base>
inline bool instanceof(const Base*) {
   return std::is_base_of<Base, T>::value;
}

现在,话虽如此,这instanceof()仍然没有做正确的事情。std::is_base_of编译时检查,但您不能在编译时检查多态对象类型,因为编译器不知道基指针实际指向的派生类型。它只知道指针本身的类型。

假设您定义了另一个类,该类Plus也派生自Operation,然后将该其他类的克隆传递给您的版本instanceof()std::is_base_of<Operation, Plus>::value即使该对象实际上不是 的实例,它仍然为真Plus

为了解决这个问题,您需要在运行时dynamic_cast检查对象类型,例如:

template<typename T, typename Base>
inline bool instanceof(const Base *b) {
   return dynamic_cast<const T*>(b) != nullptr;
}

在线演示


推荐阅读