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


当前回答

虽然虚拟是定义接口的事实标准,但我们不要忘记经典的类C模式,它在C++中带有构造函数:

struct IButton
{
    void (*click)(); // might be std::function(void()) if you prefer

    IButton( void (*click_)() )
    : click(click_)
    {
    }
};

// call as:
// (button.*click)();

这样做的优点是,您可以在运行时重新绑定事件,而无需再次构造类(因为C++没有用于更改多态类型的语法,这是变色龙类的一种变通方法)。

提示:

您可以将其作为基类继承(允许虚拟和非虚拟),并在后代的构造函数中填充单击。您可以将函数指针作为受保护的成员,并具有公共引用和/或getter。如上所述,这允许您在运行时切换实现。因此,这也是一种管理状态的方法。根据代码中ifs与状态变化的数量,这可能比switch()es或ifs更快(预计周转时间在3-4个ifs左右,但始终要先测量。如果在函数指针上选择std::function<>,则可能能够管理IBase中的所有对象数据。从这一点开始,您可以获得IBase的值示意图(例如,std::vector<IBase>将起作用)。注意,根据编译器和STL代码的不同,这可能会更慢;此外,与函数指针甚至虚拟函数相比,std::function<>的当前实现往往会有开销(这在将来可能会改变)。

其他回答

我的答案与其他人基本相同,但我认为还有两件重要的事情要做:

如果有人试图删除IDemo类型的对象,请在接口中声明一个虚拟析构函数或创建一个受保护的非虚拟析构器,以避免未定义的行为。使用虚拟继承来避免多重继承的问题。(当我们使用接口时,通常会有多重继承。)

和其他答案一样:

使用纯虚拟方法创建类。通过创建另一个重写这些虚拟方法的类来使用该接口。类IDemo{公众:虚空OverrideMe()=0;virtual~IDemo(){}}或类IDemo{公众:虚空OverrideMe()=0;受保护的:~IDemo(){}}和class Child:虚拟公共IDemo{公众:虚拟空OverrideMe(){//做一些事情}}

使用纯虚拟方法创建类。通过创建另一个重写这些虚拟方法的类来使用该接口。

纯虚拟方法是定义为虚拟并分配给0的类方法。

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

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

在C++20中,可以使用概念而不是类。它比继承更有效率。

template <class T>
concept MyInterface = requires (T t) {
    { t.interfaceMethod() };
};

class Implementation {
public:
    void interfaceMethod();
};
static_assert(MyInterface<Implementation>);

然后您可以在函数中使用它:

void myFunction(MyInterface auto& arg);

限制是不能在容器中使用它。

除了C#/Java中的抽象基类之外,您还有一个特殊的接口类型类别,这是因为C#/Java不支持多重继承。

C++支持多重继承,因此不需要特殊类型。没有非抽象(纯虚拟)方法的抽象基类在功能上等同于C#/Java接口。

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()定义接口的,另外两个类实现了相同的函数,但使用了不同的算法来计算特定于形状的面积。