如何使用 QObject 派生类实例遵循 OOP 基本概念?

Posted

技术标签:

【中文标题】如何使用 QObject 派生类实例遵循 OOP 基本概念?【英文标题】:How can I follow OOP base concepts with QObject derived class instance? 【发布时间】:2014-05-08 21:46:34 【问题描述】:

大家好...我使用 Qt 的时间不长,但最近我想到了一个想法。 QObject 具有公共函数 children() 和其他一些函数,它们将 pointer 返回到子对象。 所以自定义类的任何客户端都可以打破封装

    如何保护我的代码免受这种野蛮对待?

    为什么 Qt 开发人员将此类功能保留在公共部分? 他们试图达到什么目的?

我能想象到的关于这些函数的唯一一个论点是与 Qt 中的“垃圾收集”有关(当一个删除父级 QObject 派生类实例时,所有子实例都会被自动删除)。但我认为可以使用 Qt 的metaObject 系统来完成(我不确定机制,但是,在我看来,对子对象的访问不应该是公开的)。

    另外,考虑当有人试图在单独的线程中使用子对象时的情况,这在 Qt 中是被禁止的......但我没有看到使用 QObject::children() 的任何限制。

//--------------------------------------------- -------------------------------------------------- -

根据一些cmets的进一步解释:

虽然您可以通过 QObject::children() 访问班级的私人成员,例如

class MyClass: public QWidget private: QLabel* m_lbl1; ;
...
MyClass* p = new MyClass;
QLabel* pLbl = p->findChild<QLabel>();

不需要将成员 m_lbl1 声明为私有成员:

class MyClass: public QWidget public: QLabel* m_lbl1; ;

而且非常糟糕。因为如果您的解决方案中至少有 10^5 行代码并且超过 1 个开发人员,迟早有人可以手动更改 MyClass 的任何子成员的状态,并且您可以实现任何类型的错误(例如行为是根据MyClass 实现是不可能的)。

@Merlin069:pImpl 是 Qt 开发中常用的方法吗?

【问题讨论】:

我相信这是Qt's Object Trees 架构的一部分,我个人觉得它非常聪明。我不明白您所说的“破坏封装”或“保护您的代码免受此类处理”是什么意思。你能详细说明一下吗?你担心什么“治疗”?请注意,Qt 是基于 C++ 构建的,它不是一种“托管”语言,因此您需要确保您的代码不会“野蛮”地处理任何事情。 【参考方案1】:

Qt 对象的父系统非常有用,但我想我明白你得到了什么。

例如,假设这里声明的所有对象都是从 QObject 派生的:-

class MyClass : public QObject

    Q_OBJECT

    private:
        SomeOtherClass* m_pOtherClass = nullptr; // C++ 11 initialisation
;

在MyClass的构造函数中...

m_pOtherClass = new SomeOtherClass(this);

所以,我们现在有了封装的 SomeOtherClass 对象,但由于它的父级是 MyClass,它也可以通过 MyClass 中的函数 children() 访问。

如果你想在这里封装,那么你可以牺牲使用父/子层次结构并将 SomeOtherClass 声明为 NULL 父级。

但是,如果您考虑 Qt 的对象树的原因,正如@deGoot 所提到的,那么它提供了这样一个有用的系统,其好处超过了打破封装。

现在,如果我们真的想维护封装并使用 QObject 父系统,我们可以使用私有实现 (pimpl) 来实现,您可以 read about here。另外,在内部,Qt uses this too。

【讨论】:

我一直发现 pimpl 是在 C++ 中实现封装的最佳方式。如果你在头文件中“暴露”你的类的私有成员,总是有人可以使用指针操作来破坏封装。 Pimpl 被 Qt大量使用。如果您查看他们的源代码(毕竟它是开源的),您会发现大多数私有数据都隐藏在“公共”对象中引用的私有对象中。

以上是关于如何使用 QObject 派生类实例遵循 OOP 基本概念?的主要内容,如果未能解决你的问题,请参考以下文章

在 QObject 派生类的构造函数中使用 deleteLater

缺少带有 QObject 的派生类

OOP

如果 QObject 是从 DIRECTLY 派生的,那么使用 *virtual* 多重继承是不是安全?

OOP识别派生对象[重复]

非 QObject 内的 Qt 容器