[英]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.