std::映射和私有构造函数

std::map and private constructor

本文关键字:构造函数 映射 std      更新时间:2023-10-16

这里有一个不编译的代码:

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

问题是"map"不是B的朋友,所以它可能不会使用构造函数B()(顺便说一句,我注意到objects[2]=B(3);需要B()!)。

我找到了以下解决方法:

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

哪个有效。。。直到CCD_ 5也是私有的。

那么,当B的构造函数和析构函数是私有的时,有没有办法在A内部构建B的映射?

附加问题:为什么objects[2]=B(3);使用B()

严格来说,它不是你问题的答案,但我认为它以一种更优雅的方式解决了你的问题。

与其把B的所有字段都设为私有字段,然后在A中篡改friend关键字,不如把B类设为私有成员类来向外界隐藏:

#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 中

看看这个链接http://www.cplusplus.com/reference/map/map/operator[]/,上面写着

对该函数的调用相当于:

(*((this->insert(make_pair(k,mapped_type()))).first)).second

默认构造函数是从类std::map的作用域内调用的,该作用域不是该类的朋友。因此出现了错误。

错误应该存在。这样的构造函数不应该被声明为私有的。

解决这个问题的另一种方法是将对象的构造委托给类A,并具有指向B的指针(或引用包装器)的整数映射。然后,该映射应该只能通过A公开的接口访问。这样,B对象的整个生命周期都由A管理,并且不会破坏不变量。