考虑类的接口的以下框架。我正在介绍两种情况,一种使用shared_ptr<T>
,另一种使用unique_ptr<T>
。可实例化的用户定义类型是非模板。只有基本构造函数是模板化的,因为它需要知道派生类型来存储指向它的指针。我没有显示用于检查模板参数是否为父类的派生类型的标准库,以使代码更简单易读。
class Foo;
template<typename DerivedType>
class Base {
protected:
std::shared_ptr<DerivedType> derived_ptr_{nullptr};
Foo internal_object_{};
public:
virtual ~Base() {};
std::shard_ptr<DerivedType> derived_ptr() { return derived_ptr_; }
Foo* { return &internal_object_; }
virtual void initialize(/*.../*) = 0;
virtual void create(/*...*/) = 0;
virtual void copyTo(/*...*/) = 0;
virtual void update(/*...*/) = 0;
virtual void cleanup() = 0;
protected:
Base() = default;
};
class Derived : public Base<class Derived> {
public:
virtual ~Derived() = default;
Derived() = default;
virtual void initialize(/*.../*) override {/*...*/};
virtual void create(/*...*/) override{
/*...*/
// After all creation is successful!
derived_ptr_ = std::make_shared<Derived>(*this);
};
virtual void copyTo(/*...*/) override{/*...*/};
virtual void update(/*...*/) override{/*...*/};
virtual void cleanup() override{/*...*};
}
以上编译。我尚未针对链接或运行时进行过测试,但可以编译。
[现在让我们考虑情况二,除了std::shared_ptr<T>
的所有实例都被替换为std::unqiue_ptr<T>
作为基类中的成员变量,getter以及智能指针的赋值或创建之外,其他所有内容都与上面的完全相同使用ptr = std::make_unique<T>(*this)
。在Visual Studio 2017中std::unique_ptr<T>
编译的情况下(将编译器语言标志设置为/std:c++latest
会生成此编译器错误除外):
注意:-我的项目中类的名称分别是Buffer和VertexBuffer。与您从上面的示例中看到的相比,这是唯一的主要区别之一。为了简单起见,我和他们将它们从名称空间中删除。我还删除了对模板参数的检查,以确保其参数类型是基类的派生类型。
1>------ Build started: Project: Force Engine, Configuration: Debug x64 ------
1>Buffer.cpp
1>c:\users\..\buffer.h(62): error C2440: '<function-style-cast>': cannot convert from 'VertexBuffer' to 'std::unique_ptr<BufferClassType,std::default_delete<_Ty>>'
1> with
1> [
1> BufferClassType=VertexBuffer,
1> _Ty=VertexBuffer
1> ]
1>c:\users\...\buffer.h(62): note: No constructor could take the source type, or constructor overload resolution was ambiguous
1>Done building project "Force Engine.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
我很好奇为什么在std::shared_ptr<T>
情况下会编译,但在std::unique_ptr<T>
情况下却无法编译。是什么导致它失败,如何解决此问题,并且有解决此问题的方法。我知道我可以使用std::shared_ptr
并将其传递回需要它的调用者,但我并不特别希望此指针的“引用”计数。我希望父类(拥有)派生类的指针,同时提供一个接口,以允许外部调用者对其进行访问。在观察者的上下文中或可以选择创建自己的指针,但是永远不要成为对象的所有者。包含派生类实例的一个或多个类将拥有派生类本身,但不拥有其内部指针。此编译器错误是否与unique_ptr
无法复制等事实有关?
std::make_unique<Derived>(*this)
尝试复制构造Derived
的实例。但是Derived
是不可复制的,因为它的基类Base<Derived>
是不可复制的,因为它的数据成员std::unique_ptr<DerivedType> derived_ptr_
是不可复制的,因为std::unique_ptr
是不可复制的。