你如何在C ++中聲明一個接口?

如何設置表明接口的類? 這只是一個抽象的基類嗎? html


#1樓

若是您使用的是Microsoft的C ++編譯器,那麼您能夠執行如下操做: java

struct __declspec(novtable) IFoo
{
    virtual void Bar() = 0;
};

class Child : public IFoo
{
public:
    virtual void Bar() override { /* Do Something */ }
}

我喜歡這種方法,由於它會致使更小的接口代碼,而且生成的代碼大小能夠顯着縮小。 使用novtable刪除對該類中vtable指針的全部引用,所以您永遠不能直接實例化它。 請參閱此處的文檔 - novtablegit


#2樓

在C ++ 11中,您能夠輕鬆地徹底避免繼承: github

struct Interface {
  explicit Interface(SomeType& other)
  : foo([=](){ return other.my_foo(); }), 
    bar([=](){ return other.my_bar(); }), /*...*/ {}
  explicit Interface(SomeOtherType& other)
  : foo([=](){ return other.some_foo(); }), 
    bar([=](){ return other.some_bar(); }), /*...*/ {}
  // you can add more types here...

  // or use a generic constructor:
  template<class T>
  explicit Interface(T& other)
  : foo([=](){ return other.foo(); }), 
    bar([=](){ return other.bar(); }), /*...*/ {}

  const std::function<void(std::string)> foo;
  const std::function<void(std::string)> bar;
  // ...
};

在這種狀況下,接口具備引用語義,即您必須確保對象比接口更長(也可使接口具備值語義)。 算法

這些類型的接口有它們的優勢和缺點: 編程

  • 它們須要比基於繼承的多態性更多的內存
  • 它們一般比基於繼承的多態更快
  • 在您瞭解最終類型的狀況下, 它們會更快! (像gcc和clang這樣的編譯器在沒有/繼承具備虛函數的類型的類型中執行更多優化)。

最後,繼承是複雜軟件設計中全部邪惡的根源。 在Sean Parent的Value Semantics和基於概念的多態性中 (強烈推薦,此技術的更好版本在那裏解釋),研究瞭如下案例: 設計模式

假設我有一個應用程序,我使用MyShape接口以多態方式處理個人形狀: ide

struct MyShape { virtual void my_draw() = 0; };
struct Circle : MyShape { void my_draw() { /* ... */ } };
// more shapes: e.g. triangle

在您的應用程序中,使用YourShape界面對不一樣形狀執行相同操做: wordpress

struct YourShape { virtual void your_draw() = 0; };
struct Square : YourShape { void your_draw() { /* ... */ } };
/// some more shapes here...

如今說你想使用我在你的應用程序中開發的一些形狀。 從概念上講,咱們的形狀具備相同的界面,但爲了使個人形狀在您的應用程序中工做,您須要擴展個人形狀以下: 函數

struct Circle : MyShape, YourShape { 
  void my_draw() { /*stays the same*/ };
  void your_draw() { my_draw(); }
};

首先,根本不可能修改個人形狀。 此外,多重繼承引領了意大利麪條代碼的道路(想象一下,第三個項目就是使用了TheirShape界面......若是他們也調用了他們的繪圖函數my_draw會發生什麼?)。

更新:有一些關於基於非繼承的多態性的新引用:


#3樓

class Shape 
{
public:
   // pure virtual function providing interface framework.
   virtual int getArea() = 0;
   void setWidth(int w)
   {
      width = w;
   }
   void setHeight(int h)
   {
      height = h;
   }
protected:
    int width;
    int height;
};

class Rectangle: public Shape
{
public:
    int getArea()
    { 
        return (width * height); 
    }
};
class Triangle: public Shape
{
public:
    int getArea()
    { 
        return (width * height)/2; 
    }
};

int main(void)
{
     Rectangle Rect;
     Triangle  Tri;

     Rect.setWidth(5);
     Rect.setHeight(7);

     cout << "Rectangle area: " << Rect.getArea() << endl;

     Tri.setWidth(5);
     Tri.setHeight(7);

     cout << "Triangle area: " << Tri.getArea() << endl; 

     return 0;
}

結果:矩形區域:35三角形區域:17

咱們已經看到抽象類如何根據getArea()定義接口,另外兩個類實現相同的函數,但使用不一樣的算法來計算特定於形狀的區域。


#4樓

用純虛方法建立一個類。 經過建立覆蓋這些虛擬方法的另外一個類來使用該接口。

純虛方法是一種定義爲虛擬並分配給0的類方法。

class IDemo
{
    public:
        virtual ~IDemo() {}
        virtual void OverrideMe() = 0;
};

class Child : public IDemo
{
    public:
        virtual void OverrideMe()
        {
            //do stuff
        }
};

#5樓

除了C#/ Java中的抽象基類以外,你有一個特殊的接口類型類的所有緣由是由於C#/ Java不支持多重繼承。

C ++支持多重繼承,所以不須要特殊類型。 沒有非抽象(純虛擬)方法的抽象基類在功能上等同於C#/ Java接口。

相關文章
相關標籤/搜索