提供纯虚函数的定义

Providing a definition for a pure-virtual function

我是一名 Java 程序员,对为纯虚函数提供定义这一事实感到困惑。在 Java 中,我习惯于将抽象方法视为我们将在基础 class 中提供定义的方法。但是下面的代码是完全有效的:

#include <iostream>

struct A
{
   virtual ~A() = 0;
};

A::~A(){ std::cout << "~A()" << std::endl; }

struct B : A
{
    ~B(){ std::cout << "~B()" << std::endl; }
};

A *a = new B;


int main()
{
    delete a;
}

但是如果我们尝试这样做:

#include <iostream>

struct A
{
   virtual ~A() = 0;
   virtual void foo() = 0;
};

void A::foo(){ }
A::~A(){ std::cout << "~A()" << std::endl; }

struct B : A
{
    ~B(){ std::cout << "~B()" << std::endl; }
};

A *a = new B;


int main()
{
    delete a;
}

编译器会抱怨没有为纯虚函数提供定义。为什么我们可以在命名空间范围内定义纯虚拟析构函数,但不能为普通成员函数这样做。

这是例外而不是规则吗?

您可以定义任何纯虚成员函数。但是,即使你定义了A::foo,它仍然是纯粹的,所以AB仍然是抽象的类,可能不会被实例化。这将是您的编译器可能发出的任何错误的原因。

您显然对第二版代码中的错误原因感到困惑。

在命名空间范围内为纯虚函数(任何纯虚函数)提供定义没有错。它是析构函数还是常规函数并不重要。没有编译器会抱怨这一点。

您在第二版代码中提供的 A::foo 的定义是完全合法的,不会引起编译器的投诉。您的第二个代码的唯一问题是 B 不会覆盖 foo。因此 B 仍然是一个抽象 class。而您正在尝试实例化它。

在代码的第一个版本中,唯一继承自 A 的纯函数 B 是析构函数,并且在 B 中提供了析构函数的非纯定义。因此,B 不再是抽象的 class 并且可以合法实例化。

在代码的第二个版本中 BA 继承了两个纯虚函数——析构函数和 foo。由于您没有覆盖 B 中的 fooB 仍然是一个抽象 class,无法实例化。

仅此而已。该错误与在命名空间范围内为纯虚函数提供主体的能力无关。

当我使用 g++ 4.8.2 编译上述程序时,我得到以下消息:

编译命令:

g++ -Wall -std=c++11     socc.cc   -o socc

错误信息:

socc.cc:17:12: error: cannot allocate an object of abstract type ‘B’
 A *a = new B;
            ^
socc.cc:12:8: note:   because the following virtual functions are pure within ‘B’:
 struct B : A
        ^
socc.cc:9:6: note:  virtual void A::foo()
 void A::foo(){ }
      ^
make: *** [socc] Error 1

错误消息的要点是 B 是一个抽象类型,因为它不提供覆盖 void foo();,它在基础 [=26] 中声明为纯虚函数=].

A::foo()的定义不违法。以下程序运行良好:

#include <iostream>

struct A
{
   virtual ~A() = 0;
   virtual void foo() = 0;
};

void A::foo(){ }
A::~A(){ std::cout << "~A()" << std::endl; }

struct B : A
{
    ~B(){ std::cout << "~B()" << std::endl; }
     void foo() {}  // Need this to be able to instantiate B.
};

A *a = new B;

int main()
{
    delete a;
}