2017-09-29 19 views
1

'WindowList'クラスでウィンドウを管理しようとすると循環依存性に問題があります。下のcloseButtonPressedコードでウィンドウを閉じる場合は、windowListファイルからオブジェクトを削除する必要がありますが、WindowListterをWindowListファイルに含めています。このような以前のエラーは、前方宣言によって解決できましたが、私はこの問題を解決する方法がわかりません。 Annyの提案? (完全なコードはここで見ることができます:https://gist.github.com/anonymous/7d43c6d5b2cf1fef618be9f75077ad0c不完全な型InNested名前指定子JUCE

#pragma once 

#include "../JuceLibraryCode/JuceHeader.h" 
#include "WindowList.h" 
class WindowList; 

class WindowSetter : public DialogWindow 
{ 
public: 
WindowSetter (const String& title, 
      Component* content, 
      bool shouldBeResizeable, 
      int initWidth, int initHeight, 
      int minWidth, int minHeight, 
      int maxWidth, int maxHeight) 
: DialogWindow (title, Colours::white, true, true), 
    owner (this) 
{ 
    setUsingNativeTitleBar (true); 
    setResizable (true, true); 
    setResizeLimits (minWidth, minHeight, maxWidth, maxHeight); 
    setContentOwned (content, false); 

    setVisible (true); 


} 

~WindowSetter() 
{ 
} 

void closeButtonPressed() override 
{ 
    WindowList::getWindowList();  // ERROR: Incomplete type 'WindowList' named in nested name specifier 
    owner = nullptr; 
} 

bool escapeKeyPressed() override 
{ 
    return true; 
} 

private: 
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowSetter) 

ScopedPointer<Component> owner; 
}; 

enter image description here

編集:ファイルの完全なコードエラーの原因とエラーログのスクリーンショット

答えて

2

OMGtechyの応答はあなたが尋ねた質問に対処しますが、私は違うデザインをお勧めしたいこと:

  1. は、より多くの慣用的なJUCEコードです循環依存関係を心配する必要がなくなります。

ここでのデザインは、物事を緊密に結びつけています。この問題を解決するには、より密接な結びつきを取り除くために、ChangeBroadcaster/ChangeListenerクラスを使用することです。 WindowListWindowSetterを追加すると、その変更メッセージも購読します。ユーザーが閉じるボタンをクリックすると、WindowSetterはブール値を設定し、それが更新されたことを誰かに警告します。あなたはJUCEのコードベースではほぼどこでも使用される設計のこの種を見ることができます

class WindowSetter : public DialogWindow 
        , public ChangeBroadcaster 

{ 
public: 
    WindowSetter(/*(etc...)*/) 
    : DialogWindow(...) 
    , owner(this) 
    , wantsToClose(false) 
    { 
     // etc 

    } 

    void closeButtonPressed() override 
    { 
     wantsToClose = true; 
     // notify observers that we've changed. 
     sendChangeMessage(); 
    } 

    bool windowWantsToClose() const 
    { 
     return wantstoClose; 
    } 

private: 
    bool wantsToClose; 
}; 


class WindowList : public ChangeListener 
{ 

    void addWindowSetterToList(WindowSetter* wnd) 
    { 
     wnd->addChangeListener(this) 
     windows.addIfNotAlreadyThere(wnd); 
    } 

    void changeListenerCallback(ChangeBroadcaster* src) override 
    { 
     // cast from the ChangeBroadcaster base class to our WindowSetter class. 
     WindowSetter* wnd = dynamic_cast<WindowSetter*>(src); 
     if (nullptr != wnd) 
     { 
     // if we contain the object, and the object wants to be closed... 
     if (windows.contains(wnd) && wnd->windowWantsToClose()) 
     { 
      // get rid of it. 
      windows.remove(wnd); 
     } 
     } 
    } 

}; 

のようなスケッチで

は、それが見えます。

+0

これはちょうど私が探している解決策の一種です! JUCE/C++のhello worldよりもまだまだ新しいこと – Jefferson

+1

JUCEのサンプルのソースを読んでいる時間が何度も繰り返されます。 – bgporter

1

を追加しましたのは、あなたを見てみましょう想像上のコンパイラの視点から、何が起こっているのかを調べるためのコードです。

確かに、さんは、そのファイルを見て行くと、ここでそれを含める...

// NOTE: we're in WindowList.h 

#include "WindowSetter.h" 

確実なこと、のを見て行きましょう...

// NOTE: we're back in WindowSetter.h 

#include "WindowList.h" 

をしかし...私はやっていましたそれ。ああ、私は無限ループに入っています。助けて!

KABOOM

両者が無限ループにお互いを必要とするため、コンパイラは、あなたが求めているのヘッダーを含めることはできません。この再帰的な方法でヘッダーを含めないことで、このサイクルを中断する必要があります。

あなたがすでに知っている前方宣言は、このために役立ちます。その理由は、ヘッダーを含める必要なく型名についてコンパイラーに通知できるからです。これはコンパイラがタイプ名について知っている必要があるだけで、他のもの(例えばサイズなど)を知っている必要があるなら、これは素晴らしいことです。あなたがヘッダを含むことになった理由は、おそらくです

WindowList::getWindowList();  // ERROR: Incomplete type 'WindowList' named in nested name specifier 

あなたががここに持っている問題はさておき、建築の問題は、あなたがここにWindowSetterWindowListの内部を使用しているということです最初の場所;もしあなたがそうしなければ、それはあなたに同様のエラーを与えるでしょう。

この問題を回避するには、メンバー関数closeButtonPressed()の定義をヘッダーファイルの外側と.cppファイルに移動できます。一貫性のために他の機能も移動したいと思うかもしれません(個人的な意見)。

これを実行すると、もうWindowSetter.hの中にWindowListの詳細が使用されなくなるため、これを含めることができなくなります。

これは、他の場所に隠されている他の循環依存性がない限り、問題を解決します(私はそれをすべて読んでいません)。

+1

このような詳細な説明をありがとうOMGtech!問題は私が付属のものを使っていたやり方と関係していたと思ったが、そのような問題に近づくための「標準的な」方法は何か分かっていなかった。最初にこれらの問題に対処する必要性を避けるための今後の提案はありますか? – Jefferson

+1

私は@bgporterが大部分をカバーしていると思います:)あなたはインタフェースについても考えることができる余分なものが1つあります。インターフェイスを定義し、このインターフェイスに準拠している不明な型のオブジェクトをクラスに持ちます。そうすれば、あなたはどんな授業を受けても気にしません。何ができるのか心配しています。それ以外は、このようなミスをして、彼らから学ぶ;)間違いは、怪しいモンスターではなく、機会である。 – OMGtechy

関連する問題