【问题标题】:Providing a definition for a pure-virtual function为纯虚函数提供定义
【发布时间】:2015-08-25 03:52:46
【问题描述】:

我是一名 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;
}

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

这是一个例外而不是一个规则?

【问题讨论】:

  • 什么?为纯虚函数提供定义是完全合法的。编译器永远不会抱怨这一点。第二个代码的唯一问题是您试图实例化抽象类B,而不是为纯函数提供定义。
  • @AnT 但我是在命名空间范围内完成的。我提供了这个定义,有什么问题?
  • 在哪里?我在任何地方都没有看到B::foo 的定义。 A::foo 是一个纯虚函数。除非你用B::foo 覆盖它,否则它在B 中也将保持纯净。

标签: c++ virtual


【解决方案1】:

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

【讨论】:

  • 那么,如果我们重写它的纯虚函数,这个类就不再是抽象的了吗?但在析构函数的情况下,我们没有这样做,我们只提供了虚拟析构函数的定义。
  • @St.Antario:是的,当你用非纯函数覆盖它的所有虚函数时,这个类就不再是抽象的了。你的“我们没有那样做”到底是什么意思?是的,我们确实这样做了。当您在B 中编写非纯析构函数时,您覆盖 A 的纯析构函数。即使析构函数名称不同,析构函数仍然总是相互覆盖。它们在这方面很特别。
  • @St.Antario 是的,如果在 B 类中声明它的所有成员函数都是非纯的并覆盖从基类继承的所有纯成员函数,那么 B 将不会是抽象的。请注意,对于析构函数,当您不自己声明它时,这会自动发生。
  • 我明白了。关键是 10.3/6 即使没有继承析构函数,派生类中的析构函数也会覆盖声明为虚拟的基类析构函数;
【解决方案2】:

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

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

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

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

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

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

【讨论】:

  • 等等,我提供了虚成员函数的定义,因此 A 和 B 不是日志抽象。
  • @St.Antario:不。为纯虚函数提供主体不会“不纯”该函数。函数保持纯粹,类保持抽象。 A 类在两个版本的代码中都是抽象的。 B 类在第二版代码中是抽象的。
【解决方案3】:

当我使用 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;
}

【讨论】:

    猜你喜欢
    • 2012-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-09
    • 1970-01-01
    相关资源
    最近更新 更多