提供纯虚函数的定义

问题描述 投票:0回答:3

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

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

这是例外而不是规则?

c++ virtual
3个回答
5
投票

您可以定义任何纯虚成员函数。但是,即使您定义了

A::foo
,它仍然是纯的,因此
A
B
仍然是抽象类,可能不会被实例化。这将是您的编译器可能发出的任何错误的原因。


2
投票

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

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

您在代码的第二个版本中提供的

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

在代码的第一个版本中,唯一从

B
继承的纯函数
A
是析构函数,并且在
B
中提供了析构函数的非纯定义。所以,
B
不再是抽象类,可以合法实例化。

在代码的第二个版本中,

B
A
继承了两个纯虚函数 - 析构函数和
foo
。由于您没有在
foo
中重写
B
,因此
B
仍然是一个抽象类,无法实例化。

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


1
投票

当我使用 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;
}
© www.soinside.com 2019 - 2024. All rights reserved.