提供纯虚函数的定义

Providing a definition for a pure-virtual function

本文关键字:定义 函数      更新时间:2023-10-16

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

#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仍然是一个抽象类。您正在尝试实例化它。

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

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

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

当我使用 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();,在基类中声明为纯虚函数。

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;
}