如何从友元函数访问受保护的构造函数?

How can I access a protected constructor from a friend function?

我创建了一个 class,我想强迫任何试图构建对象的人使用 unique_ptr。为此,我想到了声明构造函数 protected 并使用 friend 函数 returns 和 unique_ptr。所以这是我想做的一个例子:

template <typename T>
class A
{
public:
    friend std::unique_ptr<A<T>> CreateA<T>(int myarg);

protected:
    A(int myarg) {}
};

template <typename T>
std::unique_ptr<A<T>> CreateA(int myarg)
{
    // Since I declared CreateA as a friend I thought I
    // would be able to do that
    return std::make_unique<A<T>>(myarg);
}

我阅读了一些有关友元函数的资料,了解到友元函数提供了对 class.

对象的 private/protected 成员的访问权限

有什么方法可以使我的示例起作用吗?

即使没有友元函数,我的目标也是让CreateA成为某人创建对象的唯一方式。

编辑

我稍微修改一下代码。我没有提到我的 class 采用一个模板参数。这显然使事情变得更加复杂。

创建一个实例化受保护构造函数的静态函数。

  #include<iostream>
#include<string.h>
#include<ctype.h>
#include<math.h>
#include <memory>
using namespace std;
template< typename T >
class A
{
public:
    static void CreateA(int myarg, std::unique_ptr<A<T>>& objA, T t) {
        std::unique_ptr<A<T>> objB(new A(myarg, t));
        objA = std::move(objB);
    }

protected:
    A(int myarg, T t) {
        m_t = t;
    }

private:
    T m_t;
};

int main() {

    int myArg = 0;
    std::unique_ptr<A<int>> anotherObjA;
    A<int>::CreateA(myArg, anotherObjA, myArg);


    return 0;
}

你可以这样做:-

#include <iostream>
#include <memory>
using namespace std;
class A
{
    int arg;
public:
    friend unique_ptr<A> CreateA(int myarg);
    void showarg() { cout<<arg; }

protected:
    A(int myarg): arg(myarg) {}
};
unique_ptr<A> CreateA (int myarg)
{
    return std::unique_ptr<A>(new A(myarg));
}
int main()
{
    int x=5;
    unique_ptr<A> u = CreateA(x);
    u->showarg();
    return 0;
}

输出:-

5

如果您不想使用 friend 函数,您可以创建函数 static 并像这样调用它:-

unique_ptr<A> u = A::CreateA(x);

编辑:-

为了回复您的编辑,我重写了程序,它是这样的:-

#include <iostream>
#include <memory>
using namespace std;
template <typename T>
class A
{
    T arg;
public:
    static std::unique_ptr<A> CreateA(T myarg)
    {
        return std::unique_ptr<A>( new A(myarg) );
    }
    void showarg()
    {
        cout<<arg;
    }
protected:
    A(T myarg): arg(myarg) {}
};

int main()
{
    int x=5;
    auto u = A<int>::CreateA(x);
    u->showarg();
    return 0;
}

简单易行!!!但请记住,您不能实例化 object of A。祝你好运!!!

其他答案建议使用静态模板函数,我同意这是最好的解决方案,因为它更简单。

我的回答解释了为什么您的朋友方法不起作用以及如何正确使用朋友方法。


你的原代码有两个问题。一是 make_unique 实际上不是 A 的友元,因此调用 make_unique<A<T>>(myarg); 无法访问 A 的受保护构造函数。为避免这种情况,您可以改用 unique_ptr<A<T>>(new A(myarg))。理论上可以声明 make_unique 一个朋友,但我什至不确定正确的语法。

另一个问题是 the template friends problem。在 class 模板中,friend <function-declaration> 实际上声明了一个非模板友元。

C++ 常见问题解答提出了两种可能的解决方法。其中之一是定义内联友元函数。但是,在那种情况下,函数只能 通过参数相关查找找到。但由于该函数不以 A<T>(或 A<T> &)作为参数,因此永远无法通过这种方式找到它。所以这个选项对你的情况不可行——它更适合运算符重载。

所以唯一的解决方法是在 class 定义之前声明(并可选地定义)模板函数:

#include <memory>

template<typename T>
class A;

template <typename T>
std::unique_ptr<A<T>> CreateA(int myarg)
{
    return std::unique_ptr<A<T>>{new A<T>(myarg)};
}

template <typename T>
class A
{
    friend std::unique_ptr<A<T>> CreateA <> (int myarg);
//          refers to existing template  ^^

protected:
    A(int myarg) {}
};

int main()
{
    auto x = CreateA<int>(5);
}

注意:可以在我已经定义的地方声明CreateA,后面再放函数定义。但是,我发布的代码有效——尽管 Anew A<T>(myarg) 出现在源代码中时未被定义——因为 CreateA 在调用之前不会实例化,此时 A 将被定义。