使用受保护构造函数和复制构造函数创建 C++ 非堆工厂对象

Posted

技术标签:

【中文标题】使用受保护构造函数和复制构造函数创建 C++ 非堆工厂对象【英文标题】:C++ non heap Factory object creation with protected constructor and copy constructor 【发布时间】:2016-12-09 12:07:55 【问题描述】:

由于 RAII 特性,我希望我的对象只能放置在堆栈上,并且由于对象创建应该委托给专门的工厂,我不希望 ocpy 构造函数可以访问以供使用。

所以我做了这样的事情。

template<typename Product, Args ... >
class Creator : public Product

    public:
        static Product create(Args ... args)
        
            return Product(args ... );
        
;

class ProtectedClass

        ProtectedClass(const ProtectedClass& aThat)=delete;
        ProtectedClass& operator=(const ProtectedClass& aThat)=delete;
    protected:
        ProtectedClass()
;

class Spawner

    public:
        ProtectedClass getProtectedClass()
        
            return Creator<ProtectedClass>::create();
        


int main()

    Spawner spawner;
    //I need protectedClass to be enclosed within this frame
    ProtectedClass protectedClass = spawner.getProtectedClass(); // err copy constructor is delted

我可以做这样的事情

template<typename Product, Args ... >
class Creator : public Product

    public:
        Creator(Args ... args) : product_(args ...)
        Product& get() const
        
            return product_;
        
    private:
        Product product_;
;

class Spawner

    public:
        std::unique_ptr<Creator<ProtectedClass>> getProtectedClassCreator()
        
            return new Creator<ProtectedClass>();
        


int main()

    Spawner spawner;
    std::unique_ptr<Creator<ProtectedClass>> creator = std::move(spawner.getProtectedClassCreator());
    ProtectedClass& protectedClass = creator->get();

但看起来不太对劲。

还有什么其他方法可以解决这个问题?

【问题讨论】:

【参考方案1】:

我这样做的方法是删除副本、启用移动并允许通过任何可以创建构造键的类进行构造。

// forward declare any factories
class Spawner;

struct ProtectedClass

    class PermissionKey 
        // this is a private constructor
        PermissionKey() ;

        // make friends of the factories
        friend Spawner;
    ;

    // all this is now public.
    // because we have declared a constructor, the default constructor
    // is deleted.    
    ProtectedClass(PermissionKey) 

    // disable copies
    ProtectedClass(const ProtectedClass& aThat)=delete;
    ProtectedClass& operator=(const ProtectedClass& aThat)=delete;

    // enable moves so the factory can return it
    ProtectedClass(ProtectedClass&& aThat)=default;
    ProtectedClass& operator=(ProtectedClass&& aThat)=default;
;

class Spawner

public:
    ProtectedClass getProtectedClass()
    
        // construct our spawned object - we can create keys
        return ProtectedClass(ProtectedClass::PermissionKey());
    
;

int main()

    Spawner spawner;
    //I need protectedClass to be enclosed within this frame
    auto protectedClass = spawner.getProtectedClass(); // ok now

【讨论】:

最后我选择了 unique_ptr。当 dtor 参与每一个移动操作时,会出现很多问题。 @user1079475 你比我更了解用例。但我以为你想要堆栈上的对象? 是的,我做到了,但是将对象从方法范围移动到调用范围时太麻烦了。这些对象具有互斥体属性,并且需要在堆上移动这些互斥体等等。麻烦多多收效甚微

以上是关于使用受保护构造函数和复制构造函数创建 C++ 非堆工厂对象的主要内容,如果未能解决你的问题,请参考以下文章

为啥子类不能使用基类受保护的构造函数创建新对象?

C++:为啥我的 DerivedClass 的构造函数无法访问 BaseClass 的受保护字段?

Swig 类型映射内部构造函数到受保护

创建类的受保护构造函数有啥好处和坏处

派生类中的静态方法可以在 C++ 中调用受保护的构造函数吗?

抽象类的 C++ 保护构造函数