4. オブジェクトモデル(オブジェクトツリー)

Qt でオブジェクトを作成すると、親オブジェクト ポインターが提供されますが、この親が何をするのかを説明します。

4.1. QObject はオブジェクト ツリーの形式で編成されます。

  • QObject オブジェクトを作成すると、QObject コンストラクターが QObject ポインターをパラメーターとして受け取ることがわかりますが、このパラメーターは親オブジェクト ポインターです。

これは、QObject オブジェクトを作成するときと同じで、その親オブジェクトを指定すると、作成した QObject オブジェクトがその親オブジェクトの Children() リストに自動的に追加されます。

  • 親オブジェクトが破棄されると、このリスト内のすべてのオブジェクトも破棄されます。(ここでの親オブジェクトは、継承という意味での親クラスではないことに注意してください。)

このメカニズムは GUI プログラミングで非常に役立ちます。たとえば、ボタンには子として QShortcut オブジェクトがあります。ボタンを削除する場合は、このショートカット キーも削除する必要があります。これは合理的です。


4.2. QWidget は、画面上に表示できるすべてのコンポーネントの親クラスです。

  • QWidget は QObject を継承するため、このオブジェクト ツリーの関係も継承します。子は自動的にその親コン​​ポーネントの子コンポーネントになりますしたがって、親コンポーネントの境界によってクリップされた状態で、親コンポーネントの座標系に表示されます。たとえば、ユーザーがダイアログ ボックスを閉じ、アプリケーションがダイアログ ボックスを削除する場合、このダイアログ ボックスに属するボタンやアイコンなども一緒に削除されるようにしたいと考えています。これらはすべてダイアログ ボックスのサブコンポーネントであるため、これが当てはまります。

  • もちろん、子オブジェクトを自分で削除することもできます。子オブジェクトは親オブジェクトのリストから自動的に削除されます。たとえば、ツールバーを削除すると、そのツールバーが配置されているメイン ウィンドウはそのツールバーをそのサブオブジェクト リストから自動的に削除し、画面表示を自動的に調整します。

4.3. Qt はオブジェクト ツリーの概念を導入し、メモリの問題をある程度解決します。

  • QObject オブジェクトがヒープ上に作成されると、Qt はそのオブジェクト ツリーも作成します。ただし、オブジェクト ツリー内のオブジェクトの順序は定義されていません。これは、これらのオブジェクトが破棄される順序も未定義であることを意味します。

  • オブジェクト ツリー内の QObject オブジェクトが削除されると、そのオブジェクトに親がある場合は、親の Children() リストから自動的に削除され、子がある場合は、それぞれの子が自動的に削除されます。Qt は、QObject が 2 回削除されないことを保証します。これは破棄順序によって決まります。

QObject がスタック上に作成された場合、Qt は同じ動作を維持します。通常の状況では、これによって問題が発生することはありません。次のコード スニペットを考えてみましょう。

{
QWidget window;
QPushButton quit("Quit", &window);
}

親コンポーネントとしての window と子コンポーネントとしての quit はどちらも QObject のサブクラスです (実際、両方とも QWidget のサブクラスであり、QWidget は QObject のサブクラスです)。

このコードは正しいです。標準 C++では、ローカル オブジェクトの破棄順序は、作成順序の逆のプロセスに従う必要があるため、quit のデストラクターは 2 回呼び出されませんしたがって、このコードがスコープ外になると、最初に quit のデストラクターを呼び出し、親オブジェクト ウィンドウの子オブジェクト リストから削除してから、 window のデストラクターを呼び出します。

ただし、次のコードを使用すると:

{
QPushButton quit("Quit");
QWidget window;
quit.setParent(&window);
}

また状況が異なり、破壊命令に問題がある。上記のコードでは、親オブジェクトとしてのウィンドウが最後に作成されたオブジェクトであるため、最初に破棄されることがわかります。破棄プロセス中に、サブオブジェクト リスト内の各オブジェクトのデストラクターが呼び出されます。つまり、この時点で quit が破棄されます。その後、コードは実行を続けますが、ウィンドウが破棄された後、quit も破棄されます。これは、quit もローカル変数であり、スコープ外に出た場合には当然破棄する必要があるためです。ただし、quit デストラクターが呼び出されたのは 2 回目であり、C++ ではデストラクターを 2 回呼び出すことができないため、プログラムがクラッシュしました。

このことから、Qt のオブジェクト ツリー メカニズムはメモリの問題をある程度解決するのに役立ちますが、注意すべき点もいくつか導入していることがわかります。こうした細かい点は今後の開発過程で時々出てくると思うので、最初から良い習慣をつけておいたほうが良いと思いますが、Qtでは構築時に親オブジェクトを指定して、思い切ってヒープ上に作成してみるなどしてみましょう。


要約:

上図に示すように、Qt ではすべてのオブジェクトがオブジェクト ツリーの形式で存在します。

QObjectこれはすべてのオブジェクトの祖先であり、他の多くのクラスがそこから派生します。QWidget 、、などQMainWindow_QDialog

QWidgetボタンなど、画面に表示されるすべてのコンポーネントの親クラスです

建設のための

オブジェクトを作成するときに親オブジェクトを指定すると、作成したオブジェクトが親オブジェクトの子に自動的に追加されます。

コンストラクターの場合、最初に親クラスが構築され、次にサブクラスが構築されます。

サブクラスを先に構築し、次に親クラスを構築すると、破棄時に親クラスが破棄されるときにサブクラスも破棄されるため、サブクラスが 2 回破棄され、プログラムがクラッシュします。

そこで、Qtでは構築時に親オブジェクトを指定して、思い切ってヒープ上に作成することで、作成したオブジェクトはリリース操作を管理する必要がなく、オブジェクトツリーに配置されるようにしてみます。

破壊の場合:

オブジェクトを解放するとき、親クラスが破棄される限り、親クラスの下にあるすべての子も破棄されます。

破棄の順序は構築の順序とはまったく逆で、最初にサブクラスが破棄され、次に親クラスが破棄されます。

おすすめ

転載: blog.csdn.net/qq_63388834/article/details/134998698
おすすめ