Here's a code that doesn't compile:
#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;
}
From what I understand in the error message:
/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()));
^
the problem is "map" is not a friend of B
, so it may not use constructor B()
(incidentally I notice that objects[2]=B(3);
requires B()
!).
I found the following workaround:
objects.insert(pair<int,B>(2,B(3)));
which works... until ~B()
is also private.
So, is there a way to build a map of B
inside A
when B
's constructors and destructors are private?
Additional question: why is objects[2]=B(3);
using B()
?
Strictly speaking, it is not an answer to your question, but I think it solves your problem in a more elegant way.
Instead of making all the fields of B private and then messing with friend keyword in A, you might hide class B from outside world, by making it a private member class:
This way you still cannot construct B freely outside of the A, but A can use it in any way. This also unlocks finer granularity of encapsulation in B: some parts can be made private/protected from A. It is not the case with friend class code.
Schematically, you can think of your code as:
While my code is more like:
i.e. privateness is "factored out" of B
Take a look at this link http://www.cplusplus.com/reference/map/map/operator[]/ , it says
The default constructor is being called from within the class
std::map
's scope, which is not a friend of this class. Therefore the error.The error should be there. Such a constructor should not be declared private then.
Another way to go about solving this issue is to delegate construction of the objects to the class
A
, and have a map of integers to pointers (or reference wrappers) to B. This map should then only be accessible through an interface thatA
exposes. That way the entire lifetime of theB
objects is managed byA
and no invariants are broken.