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


当前回答

为了扩展bradtgmurray的答案,您可能希望通过添加虚拟析构函数来对接口的纯虚拟方法列表进行一个例外。这允许您将指针所有权传递给另一方,而不暴露具体的派生类。析构函数不必做任何事情,因为接口没有任何具体的成员。将函数定义为虚拟函数和内联函数可能看起来很矛盾,但相信我,事实并非如此。

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

class Parent
{
    public:
        virtual ~Parent();
};

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

您不必为虚拟析构函数包含一个主体——事实证明,某些编译器在优化空析构函数时遇到了问题,最好使用默认值。

其他回答

为了扩展bradtgmurray的答案,您可能希望通过添加虚拟析构函数来对接口的纯虚拟方法列表进行一个例外。这允许您将指针所有权传递给另一方,而不暴露具体的派生类。析构函数不必做任何事情,因为接口没有任何具体的成员。将函数定义为虚拟函数和内联函数可能看起来很矛盾,但相信我,事实并非如此。

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

class Parent
{
    public:
        virtual ~Parent();
};

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

您不必为虚拟析构函数包含一个主体——事实证明,某些编译器在优化空析构函数时遇到了问题,最好使用默认值。

以上都是好答案。还有一件事你应该记住——你也可以有一个纯粹的虚拟析构函数。唯一的区别是你仍然需要实现它。

困惑的


    --- header file ----
    class foo {
    public:
      foo() {;}
      virtual ~foo() = 0;

      virtual bool overrideMe() {return false;}
    };

    ---- source ----
    foo::~foo()
    {
    }

你想这样做的主要原因是,如果你想提供接口方法,就像我所说的那样,但让重写它们成为可选的。

要使类成为接口类,需要一个纯虚方法,但所有的虚方法都有默认实现,因此唯一剩下的方法就是析构函数。

在派生类中重新实现析构函数根本没什么大不了的——我总是在派生类里重新实现一个析构函数,不管是虚拟的还是非虚拟的。

C++中没有“接口”本身的概念。AFAIK,接口首先在Java中引入,以解决缺少多重继承的问题。事实证明,这个概念非常有用,在C++中使用抽象基类也可以达到同样的效果。

抽象基类是一个类,其中至少一个成员函数(Java语言中的方法)是使用以下语法声明的纯虚拟函数:

class A
{
  virtual void foo() = 0;
};

抽象基类不能实例化,即不能声明类A的对象。只能从A派生类,但任何不提供foo()实现的派生类也将是抽象的。为了停止抽象,派生类必须为其继承的所有纯虚拟函数提供实现。

请注意,抽象基类可以不仅仅是一个接口,因为它可以包含非纯虚拟的数据成员和成员函数。接口的等价物是一个抽象基类,没有任何数据成员,只包含纯虚拟函数。

而且,正如MarkRansom所指出的,抽象基类应该像任何基类一样提供虚拟析构函数。

考虑这一点的一个好方法是继承接口而不是继承实现。在C++中,您可以同时继承接口和实现(公共继承),也可以只继承实现(私有继承)。在Java中,您可以选择只继承接口,而不继承实现。

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

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

和其他答案一样:

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

在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);

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