微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

如何解决如何从内部类中访问私有构造函数? C++14

我正在尝试将构建器模式应用于对象,但私有构造函数在内部类中不可见。

#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 在朋友子句中是不完整的,所以我无法让它工作。我非常想将对象的实例化限制为 Builder 类,在 C++ 中有没有办法做到这一点? 还是将 Outer 构造函数设为公开是唯一的选择?

解决方法

这不起作用,因为真正的构建器是 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,因为它是一个私有类。但是它的构造函数是公共的,所以 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;
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。