2016-05-12 4 views
-1

Вот код, который не компилируется:станд :: карта и частный конструктор

#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())); 
                 ^

проблема «карта» не является друг B, поэтому он может не использовать конструктор B() (кстати, я замечаю, что objects[2]=B(3); требует B()!).

Я нашел следующий обходной путь:

objects.insert(pair<int,B>(2,B(3))); 

, который работает ... до тех пор, пока ~B() также частные.

Итак, есть ли способ построить карту B внутри A, когда конструкторы и деструкторы B являются частными?

Другой вопрос: почему objects[2]=B(3); с использованием B()?

+2

_ "Так , есть ли способ построить карту B внутри A, когда конструкторы и деструкторы B являются частными? »_ № –

+0

« * Из того, что я понимаю в сообщении об ошибке * «Какое сообщение об ошибке? – user2079303

+0

Почему downvote? –

ответ

3

Строго говоря, это не ответ на ваш вопрос, но я думаю, что он решает вашу проблему более элегантным способом.

Вместо того, чтобы все поля B приватного и затем баловаться с другом ключевым словом в А, вы можете скрыть класс 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; 
} 

Таким образом, вы до сих пор не можете построить B свободно вне A, но A может использовать его каким-либо образом. Это также открывает более тонкую гранулярность инкапсуляции в B: некоторые части могут быть сделаны частными/защищенными от A. Это не относится к коду класса друга.

Схематично, вы можете думать о своем коде, как:

A [ B [ private(a), private(b), private(c), ... ] ] 

Хотя мой код больше похож:

A[ private(B[a, b, c]) ] 

т.е. частного начала является "вынесена" из B

+0

Это именно то, что мне нужно! Я не знал о частных классах пользователей. Большое спасибо. –

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 и никаких инвариантов не нарушаются.

+1

Спасибо за ответ. Я не обсуждал актуальность ошибки, просто не понимая почему и ищу решение :-) –

+1

@ L.Levrel Я должен был опубликовать решение, которое я считал достойным! Я был занят другими вещами и не думал об этом. Я отредактирую свой ответ – Curious

+1

Это было прилично. Липоподобная цитата (так много круглых скобок!) Заставила меня внимательно изучить, что делает оператор []. Так что это было полезно. Я принял ответ Drop, который решает мою проблему, хотя он не отвечает на вопрос, строго говоря: пожалуйста, простите это мне, как новичок, я не очень хорошо выразил свой вопрос. Спасибо, что нашли время, чтобы отредактировать ваш уже поддержанный ответ, так как я не могу его дважды увеличить, я отвечу на ваш комментарий: небольшой шаг к вашему 2000 репутации! (они дают репутацию для комментариев, правда?) –

Смежные вопросы