[英]friend class cannot call private constructor
下面的代码是我今天正在使用的东西的简化版本。 它有 2 个类 A 和 B。 B 类尝试使用 A 类的私有构造函数,但失败了。 如果我将构造函数公开,则代码编译得很好。 这是为什么?
#include <vector>
class A
{
friend class B;
private:
A(int * int_ptr) {
m_int = *int_ptr;
}
private:
int m_int;
};
class B
{
friend class A;
public:
static void create_vec_a() {
int v1(1);
int v2(2);
std::vector<int *> int_ptr_vec{
&v1,
&v2
};
std::vector<A> a_vec(int_ptr_vec.begin(),
int_ptr_vec.end());
}
};
int main(int argc, char *argv[])
{
B::create_vec_a();
return 0;
}
我在 Visual Studio 中得到的错误是:
'A::A': cannot access private member declared in class 'A'
在叮当上:
test.cpp:28:18: note: in instantiation of function template specialization 'std::vector<A, std::allocator<A> >::vector<__gnu_cxx::__normal_iterator<int **, std::vector<int *, std::allocator<int *> > >, void>' requested here
std::vector<A> a_vec(int_ptr_vec.begin(),
^
test.cpp:7:2: note: declared private here
A(int * int_ptr) {
^
你必须和std::allocator<A>;
朋友std::allocator<A>;
,因为那是试图访问构造函数的人。
class A
{
friend class std::allocator<A>;
...
尽管从给定的示例中很难对整体设计发表评论,但我会考虑将其公开,因为如果 stl 可以,任何可以看到class A
都可以构造它。
对A
的构造函数的实际调用发生在std::allocator<A>::construct
,不在B
的范围内,因此您需要std::allocator<A>
成为朋友。 但是,这将允许每个人调用您的私有构造函数,这可能是不可取的。
最简单的方法(不涉及使A
的构造函数公开或有效公开)只是在B
构造A
并将它们移动到向量中。 (您显示的A
隐式声明了复制和移动构造函数。)
std::vector<A> a_vec;
for (int* p : int_ptr_vec) {
a_vec.push_back(A(p));
}
如果A
不是可移动的(很少见,但如果它包含原子变量或互斥量作为成员,则可能会发生),那么您可以考虑更复杂的访问控制技术,例如需要传递特殊令牌到构造函数。
class A
{
public:
class Token
{
friend class B;
private:
Token() {}
};
A(Token, int * int_ptr) {
m_int = *int_ptr;
}
private:
int m_int;
};
// ...
// inside B
std::vector<A> a_vec;
for (int* p : int_ptr_vec) {
a_vec.emplace_back(A::Token(), p);
}
(这种方法也可以更普遍地使用,例如,在没有友谊的语言中,如 Java。)
错误 clang 输出实际上非常具有描述性。 调用std::vector<A> a_vec(int_ptr_vec.begin(), int_ptr_vec.end());
会调用一个可以实现(非常天真)的构造函数,如下所示:
vector(TIterator _Begin, TIterator _End) {
for (auto it = _Begin; it < _End; ++it) {
this->push_back(T(*it)); // This calls the constructor you have marked as private
}
}
由于您的类中所需的构造函数被标记为私有,因此当该特定函数被编译器的模板传递扩展时,编译无法成功。
将构造函数标记为 public 是正确的做法(毕竟它是公开使用的)。
或者,您可以将构造函数保留为私有,并在创建后以其他方式手动填充向量。 编译不会失败,因为需要构造函数的模板代码不会被实例化。 就像是:
std::vector<A> a_vec;
for (auto ptr: int_ptr_vec) {
a_vec.push_back(A::create(ptr)); // Define create() in A as you wish
}
聚会迟到了,但这里有一个同事向我展示的一个技巧,可以通过简单的方式解决这个问题:
class Foo
{
// This is used to make the constructor effectively private
struct PrivateConstruct
{
};
public:
Foo(MyType myArg, PrivateConstruct);
...
};
然后从朋友类构造:
auto uniqueFoo = std::make_unique<Foo>(myValue, Foo::PrivateConstruct());
尝试在 B 类中使用朋友 A::A(int * int_ptr)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.