我是一名Java程序员,并且对于为纯虚函数提供定义这一事实感到很担心。在Java中,我习惯于将抽象方法视为方法,我们将在基类中提供deifinitions。但以下代码完全有效:
#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;
}
编译器会抱怨没有提供纯虚函数的定义。为什么我们可以在namesapace范围中定义纯虚拟析构函数,但不能为通常的成员函数执行此操作。
这是一个例外而非规则吗?
答案 0 :(得分:4)
您可以定义任何纯虚拟成员函数。但是,即使您定义A::foo
,它仍然是纯粹的,因此A
和B
仍然是抽象类,可能无法实例化。这将是编译器可能发出的任何错误的原因。
答案 1 :(得分:2)
您显然对第二版代码中出错的原因感到困惑。
在命名空间范围内为纯虚函数,任何纯虚函数提供定义没有任何问题。无论是析构函数还是常规函数都无关紧要。没有编译器会抱怨这一点。
您在代码的第二个版本中提供的A::foo
的定义完全合法,并且不会引起编译器的抱怨。第二个代码的唯一问题是B
不会覆盖foo
。因此B
仍然是一个抽象类。而你正在尝试实例化它。
在代码的第一个版本中,从B
继承的唯一纯函数A
是析构函数,而B
中提供了析构函数的非纯函数定义。所以,B
不再是抽象类,可以合法地实例化。
在代码B
的第二个版本中,继承了A
的两个纯虚函数 - 析构函数和foo
。由于您没有覆盖foo
中的B
,B
仍然是一个抽象类,无法实例化。
这就是它的全部。该错误与在命名空间范围内为纯虚函数提供正文的能力无关。
答案 2 :(得分:1)
当我使用g ++ 4.8.2编译上述程序时,我收到以下消息:
编译器命令:
{
"rules": {
"roles":{
".read": "root.child('roles').child(auth.uid).child('role').val() === 'admin'",
".write": "root.child('roles').child(auth.uid).child('role').val() === 'admin'",
"$id" : {
".read" : "$id === auth.uid"
}
},
"users": {
".read" : "root.child('roles').child(auth.uid).child('role').val() === 'admin'",
"$user":{
".read": "$user === auth.uid",
".write": "$user === auth.uid"
}
}
}
}
错误讯息:
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()