跳轉到內容

更多 C++ 慣用法/能力查詢

來自華夏公益教科書,開放書籍,為開放的世界

能力查詢

[編輯 | 編輯原始碼]

在執行時檢查物件是否支援某個介面。

將介面與實現分離是良好的面向物件軟體設計實踐。在 C++ 中,介面類 慣用法用於將介面與實現分離,並使用執行時多型性呼叫任何抽象的公共方法。擴充套件介面類慣用法中的示例,具體類可以實現多個介面,如下所示。

class Shape {  // An interface class.
  public:
    virtual ~Shape();
    virtual void draw() const = 0;
    //...
};

class Rollable {  // One more interface class.
  public:
    virtual ~Rollable();
    virtual void roll() = 0;
};

class Circle : public Shape, public Rollable {  // Circles roll - concrete class.
    //...
    void draw() const override;
    void roll() override;
    //...
};

class Square : public Shape {  // Squares don't roll - concrete class.
    //...
    void draw() const override;
    //...
};

現在,如果我們得到一個指向抽象類 Rollable 的指標的容器,我們可以簡單地對每個指標呼叫 roll 函式,如介面類慣用法中所述。

std::vector<Rollable *> rollables;
//  Fill up rollables vector somehow.
for ( Rollable * rPtr : rollables )
  rPtr->roll();

有時,我們無法提前知道物件是否實現了特定的介面。這種情況通常發生在物件從多個介面類繼承時。為了在執行時發現介面的存在與否,可以使用能力查詢。

解決方案和示例程式碼

[編輯 | 編輯原始碼]

在 C++ 中,能力查詢通常表示為在無關型別之間進行 dynamic_cast

Shape *s = getSomeShape();
if (Rollable *roller = dynamic_cast<Rollable *>(s))
  roller->roll();

這種 dynamic_cast 的用法通常稱為交叉轉換,因為它試圖跨越層次結構進行轉換,而不是向上或向下層次結構。在我們關於形狀和可滾動物件的示例層次結構中,dynamic_castRollable 僅對 Circle 成功,而對 Square 則不成功,因為後者沒有從 Rollable 介面類繼承。

過度使用能力查詢通常表明面向物件設計存在缺陷。

已知用途

[編輯 | 編輯原始碼]
  • Martin,Robert C. "無環訪問者模式" (PDF). {{cite web}}: |archive-url= requires |archive-date= (help)
[編輯 | 編輯原始碼]
華夏公益教科書