如何使用 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