这是一个没有编译的代码:
#include <map>
using namespace std;
class A;
class B {
friend class A;
int b;
B():b(1){};
B(int b_):b(b_){};
};
class A {
map<int,B> objects;
public:
void init(){
objects[2]=B(3);
}
};
int main(){
A a;
a.init();
return 0;
}
根据我在错误消息中的理解:
/usr/include/c++/4.8/bits/stl_map.h: In instantiation of ‘std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const key_type&) [with _Key = int; _Tp = B; _Compare = std::less<int>; _Alloc = std::allocator<std::pair<const int, B> >; std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type = B; std::map<_Key, _Tp, _Compare, _Alloc>::key_type = int]’:
foo.cc:18:24: required from here
foo.cc:9:10: error: ‘B::B()’ is private
B():b(1){};
^
In file included from /usr/include/c++/4.8/map:61:0,
from foo.cc:1:
/usr/include/c++/4.8/bits/stl_map.h:469:59: error: within this context
__i = insert(__i, value_type(__k, mapped_type()));
^
问题是&#34; map&#34;不是B
的朋友,因此它可能不会使用构造函数B()
(顺便提一下,我注意到objects[2]=B(3);
需要B()
!)。
我找到了以下解决方法:
objects.insert(pair<int,B>(2,B(3)));
有效......直到~B()
也是私有的。
那么,当B
的构造函数和析构函数是私有的时,有没有办法在A
内构建B
的地图?
其他问题:为什么objects[2]=B(3);
使用B()
?
答案 0 :(得分:3)
严格来说,这不是你问题的答案,但我认为它能以更优雅的方式解决你的问题。
不要将B的所有字段设为私有,然后在A中弄乱朋友关键字,您可以将B类隐藏在外部世界中,使其成为私有member class:
#include <map>
class A {
class B {
int b;
public:
B() : b(1){};
B(int b_) : b(b_){};
~B() {}
};
std::map<int, B> objects;
public:
void init() {
auto b = B();
objects[2] = B(3);
objects.insert(std::pair<int, B>(2, B(3)));
}
};
int main() {
A a;
A::B b; // 'A::B': cannot access private class declared in class 'A'
a.init();
return 0;
}
这样你仍然不能在A之外自由地构造B,但是A可以以任何方式使用它。这也解锁了B中更精细的封装粒度:某些部分可以被私有/保护免受A.友情类代码不是这种情况。
示意图,您可以将代码视为:
A [ B [ private(a), private(b), private(c), ... ] ]
虽然我的代码更像是:
A[ private(B[a, b, c]) ]
即。私有性是“B”的“因素”
答案 1 :(得分:1)
看一下这个链接http://www.cplusplus.com/reference/map/map/operator[]/,它说
对此功能的调用相当于:
(*((this->insert(make_pair(k,mapped_type()))).first)).second
默认构造函数是从类std::map
范围内调用的,该范围不是此类的朋友。因此错误。
错误应该存在。这样的构造函数不应该被声明为私有。
解决此问题的另一种方法是将对象的构造委托给类A
,并将指针(或引用包装器)的整数映射到B.这个映射应该只能访问通过A
暴露的接口。这样,B
对象的整个生命周期都由A
管理,并且没有不变量被破坏。