为什么在 C++ 中 'virtual' 和 '=0' 都需要描述一个方法是抽象的?

Why in C++ 'virtual' and '=0' is both needed to describe a method is abstract?

C++ 编程语言中所述:

virtual void push(char c) = 0;
virtual void pop() = 0;

单词virtual的意思是'may be redefined later in a class derived from this one'
=0 语法表示从 Stack 派生的一些 class 必须定义函数。

那么为什么需要 =0 符号呢?是不是说一个派生class必须定义这个函数,也就是说没有=0的时候,有些派生class不强制定义这个方法?

我对此感到困惑,需要一些帮助。

So why =0 symbol is needed?

考虑以下几点:

struct foo
{
    virtual void some() const { cout << "foo" << endl; }
};

struct bar : public foo
{
    virtual void some() const { cout << "bar << endl; }
};

struct baz : public foo
{
}

假设你有一个指针 foo *p 指向某个对象,你调用 p->some().

  • 如果p指向一个bar对象,它会打印"bar".

  • 如果p指向一个baz对象,它会打印"foo".

在某些情况下,这可能不是您想要的。您可能想要指定 any derived class 需要覆盖它。 =0 做到了。

抽象的目的class(那些class有纯虚方法=0) 是为了提供一个合适的基础 class,其他 classes 可以从中继承。抽象 classes 不能用于实例化对象,只能用作 接口 .

因此,如果需要实例化抽象 class 的子class,它 必须 实现 each的虚函数,这意味着它支持抽象声明的接口class

这是接口的基本概念。

简而言之,这是一种确保派生 class 将从基 class 实现这些方法的方法。

你的想法是对的。

So why =0 symbol is needed? Does it means that a child class must define this function, and that's to say when there is no =0, some child classes are not forced to define this method?

基本上你可以:

  • 使方法成为非虚方法

这不允许从实现该方法(通过 publicprotected)的 class 派生的任何 class 更改该方法的行为。

  • 制作方法virtual

这允许(但不强制)从实现该方法(通过 publicprotected)的 class 派生的任何 class 更改基 class 中方法的行为。您甚至不必再调用原始基础 class 方法,因此您可以根据需要进行重大更改。

  • 制作方法pure virtual ( virtual = 0 )

这强制任何从实现该方法(通过 publicprotected)的 class 派生的 class 实现某种 behavior/body 对于这种方法。如果派生 class 不提供实现,那么这个 class 将立即变成抽象本身。这允许省略基 class 中方法的 behavior/body,因此不允许直接实例化具有一个或多个纯虚拟方法的 class(抽象 class).

So why =0 symbol is needed?

具有序列 = 0 的虚函数被称为 纯虚函数 ,(序列 = 0 被称为 纯说明符),它使 class 成为无法实例化的 abstract class。对于派生的classes,如果要使其实例化成为可能,就必须实现纯虚函数。

No objects of an abstract class can be created. Abstract types cannot be used as parameter types, as function return types, or as the type of an explicit conversion. Pointers and references to an abstract class can be declared.

例如,

class Stack {
    virtual void push(char c) = 0;
};
...
Stack s; // Fail, Stack is an abstract class

如果

class Stack {
    virtual void push(char c);
};
...
Stack s; // Fine, if you won't call `push()` on it.

首先考虑使用虚方法的原因是什么

1.Interface(多态).

C++中的接口是纯虚的class,也就是说,它的所有方法都是纯虚的(就像你上面提到的这两个),它有一个虚析构函数,没有构造函数(很明显,因为我们无法创建它的实例)。它也不应该有任何数据。

让我们定义一个接口(C++ 中的纯抽象 class):

class Interface
{
public:
    virtual ~Interface(){}
    virtual void somePublicMethod() = 0;
};

并定义class,这是接口的实现:

class Implementation : public Interface
{
public:
   ~Implementation() override {}
   void somePublicMethod() override {}
};

如果在接口中定义另一个纯虚方法:

virtual void anotherPublicMethod() = 0;

如果你不在实现中覆盖它,当你声明实现类型的对象时,你会收到编译错误,因为真正的实现对象必须有所有派生方法的定义(主体)。

你还可以定义一些接口方法的默认行为:

void Interface::somePublicMethod()
{
    //define default behavior here
}

并在派生中调用它 class:

void Implementation::somePublicMethod()
{
    Interface::somePublicMethod();
}

您将在其他主题中阅读如何在多态中使用接口。

2."普通"继承。

在“普通”继承中,您应该使用虚拟方法而不是纯虚拟方法,因为您希望同时拥有 Base class 和 Derived class(es) 的实例。虚拟方法仅表示它们可以在派生 class(es).

中被覆盖

结论

一般来说,如果你想要任何 class 的实例,这个 class 必须定义所有方法(所以必须有主体,很明显它们不能是纯的虚拟)。