使用MFC对象初始化std::map编译失败的原因及解决方法
MFC中std::map包含控件对象时初始化失败的原因与解决
问题描述
在CView的头文件中尝试初始化包含MFC控件类的std::map:
// myprogramView.h std::map<int, CStatic> myMap = {{10,{}}, {11,{}}};
编译器报错:
- IntelliSense提示“没有匹配参数列表的构造函数实例”
- MSVC实际报错为C2664:无法将参数1从初始化列表转换为
std::initializer_list<std::pair<const _Kty,_Ty>>
但以下类似初始化可以正常运行:
std::map<int, std::string> myMap2 = { {10,{}}, {11,{}} }; std::map<int, std::map<std::string, int>> myMap3 = { {10,{}}, {11,{}} };
同时尝试使用MFC的CMap也遇到相同问题,需求是在运行时或OnCreate中访问map内的控件对象并调用其Create()方法。
原因分析(来自j6t的解答,注:讨论的是std::initializer_list,而非C++类的成员初始化列表)
核心原因是MFC控件类(如CStatic)的默认构造函数是受保护的(protected):
- 当用
std::initializer_list初始化std::map<int, CStatic>时,编译器需要为每个{key, {}}创建std::pair<const int, CStatic>对象,这会尝试调用CStatic的默认构造函数,但因为该构造函数是protected,外部无法直接调用,导致初始化失败。 - 而
std::string、std::map等标准库类的默认构造函数是public的,所以可以正常通过初始化列表创建对象,完成map的初始化。
解决方法
由于MFC控件对象需要与具体的HWND绑定,不能直接在map中存储值类型的控件对象,正确的做法是存储指针:
- 声明map为指针类型:
// myprogramView.h std::map<int, CStatic*> myMap;
- 在
OnCreate或其他合适的时机(确保父窗口已创建)动态创建CStatic控件,并将指针存入map:
int CMyprogramView::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CView::OnCreate(lpCreateStruct) == -1) return -1; // 创建第一个CStatic控件 CStatic* pStatic1 = new CStatic; pStatic1->Create(_T("Static 10"), WS_CHILD | WS_VISIBLE | SS_CENTER, CRect(10,10,100,30), this, 1001); myMap[10] = pStatic1; // 创建第二个CStatic控件 CStatic* pStatic2 = new CStatic; pStatic2->Create(_T("Static 11"), WS_CHILD | WS_VISIBLE | SS_CENTER, CRect(10,50,100,70), this, 1002); myMap[11] = pStatic2; return 0; }
- 注意事项:
- 控件对象的销毁:需要在窗口销毁时(如
OnDestroy)遍历map,delete每个指针,避免内存泄漏。 - 若使用智能指针(如
std::unique_ptr<CStatic>),可以自动管理内存,减少手动销毁的负担:std::map<int, std::unique_ptr<CStatic>> myMap; // 创建时: myMap[10] = std::make_unique<CStatic>(); myMap[10]->Create(...);
- 控件对象的销毁:需要在窗口销毁时(如
对于MFC的CMap,同样需要存储指针类型,而非值类型,才能避免构造函数访问权限的问题。
内容的提问来源于stack exchange,提问作者starriet 차주녕
相关产品推荐
相关产品推荐

