Qt编译错:cannot access private member declared in class 'QObject'

本文探讨了Qt基类对象QObject禁用默认拷贝构造函数的原因,并解释了为什么不应该为QObject及其子类提供拷贝构造函数。同时给出了正确的做法:如果类需要拷贝或赋值,则不应从QObject派生。

1>u:/source/hitemfile.h(174) : error C2248: 'QObject::QObject' : cannot access private member declared in class 'QObject'
1>        d:/qt/include/qtcore/../../src/corelib/kernel/qobject.h(302) : see declaration of 'QObject::QObject'
1>        d:/qt/include/qtcore/../../src/corelib/kernel/qobject.h(115) : see declaration of 'QObject'
1>        This diagnostic occurred in the compiler generated function 'HItemBase::HItemBase(const HItemBase &)'

 

 

网上可以搜索到一条讨论:http://www.qtforum.org/article/23914/QObjectQObject--cannot-access-private-member-decla.html 原因是因为Qt基类对象QObject通过宏 Q_DISABLE_COPY disable了缺省的copy constructor和operator=。但是为什么要这样做让我很费解,论坛中的解决方案是自定定义copy constructor和operator=,这样确实可以解决问题,但是岂不是违背了DISABLE_COPY的初衷?

 

下面在看看Qt文档中对于该宏的说明:

 

Q_DISABLE_COPY ( Class )

Disables the use of copy constructors and assignment operators for the given Class.

Instances of subclasses of QObject should not be thought of as values that can be copied or assigned, but as unique identities. This means that when you create your own subclass of QObject (director or indirect), you should not give it a copy constructor or an assignment operator. However, it may not enough to simply omit them from your class, because, if you mistakenly write some code that requires a copy constructor or an assignment operator (it's easy to do), your compiler will thoughtfully create it for you. You must do more.

 

看来QObject对象及其派生类是不进行copy的,也就是说,QObject对象簇理论上都不应该被copy或者赋值。然后查看了一下QString,QLine,确实不是从QObject派生而来的。既然这样,那QObject的说明“The QObject class is the base class of all Qt objects.”就当做别的理解了。

 

因此我认为Qt的论坛Qtforum.org中的解答并不正确,正确的做法是:如果你的类需要copy或者被赋值,则不要让你的类从QObject派生。

 

欢迎拍砖:)

<think>我们正在处理一个关于MFC编程中出现的编译误:C2248。根据用户提供的引用内容,误信息是: 'CObject::CObject' : cannot access private member declared in class 'CObject' 这个误通常发生在尝试复制一个从CObject派生的类对象时,因为CObject的拷贝构造函数是私有的(private)。在MFC中,许多类(如CStringArray)都是从CObject派生的,而CObject的拷贝构造函数和赋值运算符都是私有的,这意味着这些类不支持复制语义。 从引用[2]中我们可以看到,误发生在尝试复制一个CArray<POINT, POINT>对象时(在编译器生成的拷贝构造函数中)。同样,用户提供的引用[3]中有一个结构体OpStruct,其中包含了CStringArray类型的成员。如果用户试图复制这个结构体,那么就会触发这个误,因为CStringArray(以及CArray)的拷贝构造函数是私有的(它们继承了CObject的特性)。 解决方案: 1. 避免直接复制含有CObject派生类成员的对象。如果需要复制,应该提供自定义的拷贝构造函数和赋值运算符,并在其中使用深拷贝(deep copy)来复制这些成员。 2. 如果不需要复制,可以将拷贝构造函数和赋值运算符声明为私有(private)或者删除(=delete),以防止编译器自动生成。 3. 使用指针或智能指针来管理这些对象,从而避免复制。 具体到用户的情况,如果OpStruct需要被复制,则应该为该结构体提供自定义的拷贝构造函数和赋值运算符,对CStringArray和CArray等成员进行深拷贝。 例如,修改OpStruct的定义如下: ```cpp struct OpStruct { CString CurType; CString GrID; AppPageCtrlInfo AppValue; CStringArray DataName; CStringArray DataBase; // 自定义拷贝构造函数 OpStruct(const OpStruct& other) { // 对于基本类型和简单类型(如CString)可以直接赋值 CurType = other.CurType; GrID = other.GrID; AppValue = other.AppValue; // 假设AppPageCtrlInfo有适当的拷贝语义 // 对于CStringArray,需要手动复制每个元素 CopyStringArray(DataName, other.DataName); CopyStringArray(DataBase, other.DataBase); } // 自定义赋值运算符 OpStruct& operator=(const OpStruct& other) { if (this != &other) { CurType = other.CurType; GrID = other.GrID; AppValue = other.AppValue; DataName.RemoveAll(); DataBase.RemoveAll(); CopyStringArray(DataName, other.DataName); CopyStringArray(DataBase, other.DataBase); } return *this; } private: void CopyStringArray(CStringArray& dest, const CStringArray& src) { dest.RemoveAll(); for (int i = 0; i < src.GetCount(); i++) { dest.Add(src[i]); } } }; ``` 注意:上述代码中,假设AppPageCtrlInfo类支持拷贝(如果没有,也需要类似处理)。另外,我们为OpStruct提供了自定义的拷贝构造函数和赋值运算符,其中对CStringArray成员进行了深拷贝(通过复制每个元素)。 此外,如果用户不需要复制OpStruct对象,可以通过将拷贝构造函数和赋值运算符声明为私有且不实现(或者使用C++11的=delete)来阻止复制。 另一种常见情况是在使用STL容器(如std::vector)时,如果容器中存储了包含CObject派生类成员的对象,同样会遇到这个问题。解决方法同上:为包含CObject派生类成员的对象提供拷贝支持(通过深拷贝)或者存储指针(如std::vector<OpStruct*>)。 总结:C2248误通常是由于尝试复制不可复制的对象(其拷贝构造函数是私有的)引起的。解决方法是为包含这些对象的类提供自定义的拷贝构造函数和赋值运算符,实现深拷贝;或者避免复制,使用指针来传递对象。 §§相关问题§§ 1. 如何为包含MFC容器类(如CStringArray)的类实现深拷贝? 2. 在MFC中,为什么CObject的拷贝构造函数是私有的? 3. 除了深拷贝,还有哪些方法可以避免C2248误? </think>### 误 C2248: 'CObject::CObject' 的解决方案 该误是由于 MFC 中 `CObject` 类的拷贝构造函数和赋值运算符被声明为 **`private`**(禁止外部访问),当代码尝试复制包含 `CObject` 派生类(如 `CStringArray`)的对象时,编译器会阻止这种操作[^1][^2]。以下是具体解决方案: --- ### 原因分析 1. **`CObject` 的限制** MFC 的基类 `CObject` 显式禁用了拷贝构造和赋值操作(私有化),因此派生类如 `CStringArray`、`CArray` 等也无法直接复制[^1][^2]。 2. **常见触发场景** - 在结构体/类中包含 `CStringArray` 成员(如引用[3]中的 `OpStruct`)并尝试复制该结构体 - 将 `CStringArray` 对象作为函数参数按值传递 - 使用 `std::vector` 等容器存储 `CStringArray` 对象 --- ### 解决方案 #### ✅ 方法 1:改用指针或引用(推荐) 避免直接复制对象,改用指针或引用传递: ```cpp // 原误代码:按值传递结构体 void ProcessOpStruct(OpStruct data); // 触发 C2248 // 修改为指针传递 void ProcessOpStruct(const OpStruct* pData); // 或引用传递 void ProcessOpStruct(const OpStruct& data); ``` #### ✅ 方法 2:自定义深拷贝函数 为包含 `CObject` 派生成员的结构体/类实现深拷贝: ```cpp struct OpStruct { // ... 其他成员 CStringArray DataName; CStringArray DataBase; // 自定义拷贝构造函数(深拷贝) OpStruct(const OpStruct& src) { // 复制基础类型成员... CurType = src.CurType; CopyStringArray(src.DataName, DataName); // 深拷贝 CopyStringArray(src.DataBase, DataBase); } private: void CopyStringArray(const CStringArray& src, CStringArray& dest) { dest.RemoveAll(); for (int i = 0; i < src.GetSize(); ++i) dest.Add(src[i]); } }; ``` #### ✅ 方法 3:禁用默认拷贝操作 如果不需要复制对象,显式禁用拷贝构造和赋值: ```cpp struct OpStruct { // ... 成员定义 private: OpStruct(const OpStruct&); // 声明但不实现 OpStruct& operator=(const OpStruct&); // 阻止赋值 }; ``` #### ✅ 方法 4:替换为 `std::vector`(C++11+) 如果项目支持现代 C++,改用标准库容器: ```cpp #include <vector> #include <string> struct OpStruct { std::vector<std::string> DataName; // 替换 CStringArray std::vector<std::string> DataBase; // 标准容器可安全复制 }; ``` --- ### 关键注意事项 1. **MFC 容器设计原则** `CStringArray` 等 MFC 容器未实现值语义,因其内部包含资源句柄和状态信息,直接复制会导致资源管理冲突[^2]。 2. **编译误定位** 误信息中的 `CArray<TYPE,ARG_TYPE>::CArray(const CArray<TYPE,ARG_TYPE> &)` 表明编译器试图生成拷贝构造函数时失败[^2]。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值