如何从内部 class 访问私有构造函数? C++14

How to access private Constructor from within inner class? C++14

我正在尝试将构建器模式应用于一个对象,但是从内部看不到私有构造函数 class。

#include <iostream>
#include <memory>

class Outer{
private:
    Outer(void){ std::cout << "Constructed!" << std::endl; }
public:
    class Builder{
    public:
        std::unique_ptr<Outer> build(void){
            return std::make_unique<Outer>();
        }
    };
};

int main(int argc, char** agrs){
    std::unique_ptr<Outer> instance = Outer::Builder().build();
    return 0;
}

失败并出现以下错误:


In file included from /usr/include/c++/8/memory:80,
                 from scrap.cpp:2:
/usr/include/c++/8/bits/unique_ptr.h: In instantiation of ‘typename std::_MakeUniq<_Tp>::__single_object std::make_unique(_Args&& ...) [with _Tp = Outer; _Args = {}; typename std::_MakeUniq<_Tp>::__single_object = std::unique_ptr<Outer>]’:
scrap.cpp:11:35:   required from here
/usr/include/c++/8/bits/unique_ptr.h:831:30: error: ‘Outer::Outer()’ is private within this context
     { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
scrap.cpp:6:2: note: declared private here
  Outer(void){ std::cout << "Constructed!" << std::endl; }
  ^~~~~

我在定义中尝试了 friend class Outer::Builder,但是 Outer 在 friend 子句中不完整,所以我无法使用它。我非常想将对象的实例化限制为 Builder class,在 C++ 中有什么方法可以做到这一点吗? 还是让 Outer 构造函数 public 成为唯一的选择?

这行不通,因为真正的建造者是std::make_unique,它既不是朋友也不是会员。让它成为朋友是不可能的,因为你不知道它委托给什么内部函数,而且它无论如何都会破坏私有构造函数的目的。

您可以只使用裸 new 而不是 std::make_unique,它会在紧要关头工作。如果你想要共享指针而不是唯一指针,这会变得有点问题,因为性能不会那么好。

以下是如何使其适用于 unique_ptrshared_ptr 或任何其他类型的句柄。

#include <memory>

class Outer
{
    private:
        Outer();
    public:
        class Builder
        {
            private:
                class InnerOuter;
            public:
                std::unique_ptr<Outer> build();
        };
};

class Outer::Builder::InnerOuter : public Outer
{
    public:
        using Outer::Outer;
};

std::unique_ptr<Outer> Outer::Builder::build()
{
    return std::make_unique<InnerOuter>();
}

现在只有 Outer::Builder 可以引用(和构造)一个 InnerOuter,因为它是私有的 class。但是它的构造函数是public,所以std::make_unique可以访问它。

注意,InnerOuter 可以访问 Outer 的私有构造函数,因为它是 Outer 成员的成员,并且可以访问 Outer.

怎么样:

#include <iostream>
#include <memory>

class Outer{
private:
    Outer(void){ std::cout << "Constructed!" << std::endl; }
public:
    friend class std::unique_ptr<Outer> std::make_unique<Outer>();
    class Builder{
    public:
        std::unique_ptr<Outer> build(void){
            return std::make_unique<Outer>();
        }
    };
};

int main(int argc, char** agrs){
    std::unique_ptr<Outer> instance = Outer::Builder().build();
    return 0;
}

你也可以在 C++ 中创建友元函数。

根据问题中未描述的细节,还有其他方法可以解决问题。

例如,如果虚拟调用适合您,最简单的方法就是使用工厂模式。这将完全隐藏实现细节(这是使用依赖注入时的常见方法)可以构造对象,因为 Outer 是完全抽象的。

// header
#include <memory>

class Outer {
public:
    virtual ~Outer();

    virtual void fun1() = 0;
    virtual int fun2(int) = 0;

    class Builder{
    public:
        std::unique_ptr<Outer> build(void);
};
#include "Outer.h"

Outer::~Outer() = default;

class ImplOuter : public Outer {
public:

    void fun1() override {
        // todo
    }
    int fun2(int) override {
        // todo
        return 0;
    }
};

std::unique_ptr<Outer> Outer::Builder::build(void)
{
     return std::make_unique<ImplOuter>();
}
#include <iostream>
#include "Outer.h"

int main(int argc, char** agrs){
    auto instance = Outer::Builder().build();
    instance->fun1();
    return 0;
}