你如何在C ++中声明一个接口?

纵然是瞬间 提交于 2019-12-19 21:05:59

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

如何设置代表接口的类? 这只是一个抽象的基类吗?


#1楼

如果您使用的是Microsoft的C ++编译器,那么您可以执行以下操作:

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

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

我喜欢这种方法,因为它会导致更小的接口代码,并且生成的代码大小可以显着缩小。 使用novtable删除对该类中vtable指针的所有引用,因此您永远不能直接实例化它。 请参阅此处的文档 - novtable


#2楼

在C ++ 11中,您可以轻松地完全避免继承:

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接口以多态方式处理我的形状:

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

在您的应用程序中,使用YourShape界面对不同形状执行相同操作:

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接口。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!