(1)在 c++ 里,我们学到的知识是在堆区创建了一个对象后,一定要记得析构它,以回收内存,防止内存泄露。若类里有一个指针成员 T * ptrT ; ,且该成员指针指向了堆区中的类对象,则一定要在析构函数里调用语句 delete ptrT ; 来回收堆区里 T 对象占据的内存。但在 QT 里, QT 大师们设计了一套源代码,以使 QT 易学易用,以支持创建更大的项目。就引入了新的对象析构规则,如题目所示。
(2)在 c++ 语言里,按约定俗成的说法,严格的来讲 class A : public B ; 。 则这才表示 B 是 A 的父类,父对象, A 与 B 之间存在构造与析构的源代码级继承关系。父子这两个汉字,这个概念,更多的是类代码的继承关系。为了避免混淆,不应该改变父子这两个字的语义。直接把父子这两个字拿到 QT 里,来表示 “父“对象析构时可以顺带销毁“子“对象 这样的说法是欠妥当的,容易引起困惑,而且也不符合 c++ 的语法规定。 QT 里要表示这个顺带析构的含义,更准确的描述,应该是 :容器对象析构时,可以顺带销毁容器中元素。而且源码显示, QObject 基类,就是容器。所以,凡是继承了 QObject 类的子类,都将具备容器属性。
(3)给出 QObject 类的简化定义以及 QT 版智能指针类 QScopedPointer《T》的定义:
template <typename T,
typename Cleanup = QScopedPointerDeleter<T> >
class QScopedPointer //本类封装了裸指针 d,模板形参 2 指出了 类型 T 的析构函数
{ //所以从结果看,本类是类似于 STL 库里的智能指针的。
public : //本类的作用主要是防止内存泄露,以防忘记了调用类 T 的析构函数
explicit QScopedPointer(T *p = nullptr) noexcept : d(p) { }
inline ~QScopedPointer() { Cleanup::cleanup(d); }
typedef T * pointer;
T * data() const noexcept { return d; } //返回包裹的裸指针
protected : T * d; //本 QScopedPointer类实现于头文件 qscopedpointer.h
};
class Q_CORE_EXPORT QObject // export 宏表要编译本类成 dll 文件
{ //本类定义于 头文件 qobject.h
public : //可见该形参为 QObject * 指针的有参构造函数始于本 QObject基类。
explicit QObject(QObject * parent = nullptr); //实现保密,官方注释见后面
void setParent(QObject * parent);
virtual ~QObject(); //基类的正常的虚析构函数,不违背 c++ 语法
inline const QObjectList & children() const { return d_ptr->children; }
protected : //该数据成员 d_ptr 是 QObject 类的唯一数据成员,并被 QObject 的子类
QScopedPointer<QObjectData> d_ptr; //所继承。QObject 的子类也会有这些属性
}
(4)上面的 QObject 类有个智能指针类型的数据成员,该数据成员 d_ptr 指向堆区的 QObjectData 型数据结构 ,给出其定义。该类才描述了 QObject 具有的数据结构,并决定了 QObject 应该具有的功能。也就解释清楚了为啥 QT 里 QObject 类的子类都是容器:
class Q_CORE_EXPORT QObjectData
{
Q_DISABLE_COPY(QObjectData) //该宏表示禁止定义 copy 构造与 copy 赋值运算符函数
public:
QObjectData() = default;
virtual ~QObjectData() = 0;
QObject * q_ptr ; //该成员指出本类描述的是哪个 QObject 对象,回指向 QObject
QObject * parent; //记录本 QObject 类的所属容器。该功能又继承给 QObject 的所有子类
QObjectList children; //记录本 QObject 容器包含的所有 QObject 类对象
//typedef QList< QObject * > QObjectList; 类型定义
//基于此,为了处理 QT中的类对象析构,似宜将所有的类都继承 QObject并将之加入到某个容器中。
uint isWidget : 1; //以下是记录 QObject 对象应具备的其它属性,看不懂,略
uint blockSig : 1;
uint wasDeleted : 1;
uint isDeletingChildren : 1;
uint sendChildEvents : 1;
uint receiveChildEvents : 1;
uint isWindow : 1; // for QWindow
uint deleteLaterCalled : 1;
uint unused : 24;
int postedEvents;
QDynamicMetaObjectData *metaObject;
QBindingStorage bindingStorage;
QMetaObject * dynamicMetaObject() const;
#ifdef QT_DEBUG
enum { CheckForParentChildLoopsWarnDepth = 4096 };
#endif
};
++举例验证数据成员 q_ptr 的含义:
(5)补充上 QObject 类型的此有参构造函数的含义:
(6)
谢谢