簡體   English   中英

在GUI設計中避免dynamic_cast

[英]Avoiding dynamic_cast in GUI design

我正在設計GUI,但遇到了問題,因為我無法避免dynamic_casting。

我的課程:

  class Widget; //base class for all widgets

  class Container //contains widgets
  {
     std::map<std::string, Widget*> m_widgets;
     public:
     template <class T> T* get(const std::string &name)
     {
         return dynamic_cast<T*>(m_widgets.at(name)); //I need casting here
     }
   }

如何避免動態投射? 我負擔不起每種窗口小部件類型的容器,因為我的GUI必須與用戶定義的窗口小部件一起使用。 另外,我必須為每個小部件都提供一個容器,這樣用戶就不必自己存儲小部件。

為什么需要鑄造?

 class TextBox : public Widget
 { 
      public:
      std::string getText(); //I can't have it in Widget class, because it's object-specific
      //also, my gui must work with user-defined widgets so I can't provide 
      //empty virtual functions for everything in Widget
 }

我認為您不需要容納所有小部件的容器。 這些類可以保存一個指向它們需要使用的小部件的具體實例的指針。 您可以將指針作為構造函數上的參數傳遞。 另一個選擇是使用依賴注入(例如,可以將wallaroo用於您的問題)。

擴大我的評論...

根據您的代碼,我想您打算讓我為添加到Container每個子小部件指定一個字符串名稱,然后再按名稱訪問該子小部件。 因此,您希望我寫這樣的東西:

class LoginController {

    Container *container;
    static const char *kUsernameKey = "username";
    static const char *kPasswordKey = "password";

public:

    LoginController() :
        container(new Container())
    {
        container->addChild(kUsernameKey, new TextBox());
        container->addChild(kPasswordKey, new TextBox());
        container->addChild("button", new Button("Log In"));
        container->get<Button>("button")->setAction([](){
            this->login();
        })
    }

    void login() {
        string username = container->get<TextBox>(kUsernameKey)->getText();
        string password = container->get<TextBox>(kPasswordKey)->getText();
        sendLoginRequest(username, password);
    }

};

以這種方式設計Container會在運行時進行查找和類型檢查,但是可以在編譯時進行這些查找和類型檢查。

而是設計API,以便在自己的變量中保留對子代的特定類型引用。 查找孩子只是使用變量,而無需強制轉換。 查找和類型檢查在編譯時完成。 代碼如下:

class LoginController {

    Container *container;
    TextBox *usernameBox;
    TextBox *passwordBox;

public:

    LoginController() :
        container(new Container()),
        usernameBox(new TextBox()),
        passwordBox(new TextBox())
    {
        container->addChild(username);
        container->addChild(password);

        Button *button = new Button("Log In");
        container->addChild(button);
        button->setAction([](){
            this->login();
        })
    }

    void login() {
        string username = usernameBox->getText();
        string password = passwordBox->getText();
        sendLoginRequest(username, password);
    }

};

我到處都讀到RTTI不好,應該避免

我懷疑您到處都讀到這,因為那簡直是胡說八道。

RTTI是一個非常好的功能。 盡管絕對可以避免,甚至可以使用更好的工具 一個好的層次結構被設計為僅通過虛擬函數就可以訪問基類接口。 在那種情況下,您不需要任何強制轉換,只需調用虛函數即可,它將做正確的事情。

甚至您的GetText也可能是一個合理的選擇,默認實現返回一個空字符串。 也許在功能查詢工具的陪伴下,它報告實際文本的存在。 因此,大多數客戶都可以通過空字符串來結束通話,而其他人則可以進行檢查。

那些只對具體類感興趣的罕見接口的人可以永久調用dynamic_cast。 收集最好只是保持簡單並限制收集。 也許為真正常見的Widget系列添加一些特殊形式。

這里的問題是您的設計是落后的。 您想渲染一個小部件,但是該小部件沒有具體的可渲染功能。 您必須要求Widget自己渲染,它可以在任何地方渲染文本/圖像/任何內容。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM