让 A 成为 C++ 中的抽象类:
// legal
class A {
virtual void m() = 0;
}
当然,定义一个类型为抽象类的变量是非法的:
A a; // illegal
确实,clang
3.6.0 如此提示:
wat.cc:5:3: error: variable type 'A' is an abstract class
A a;
^
wat.cc:2:16: note: unimplemented pure virtual method 'm' in 'A'
virtual void m() = 0;
^
1 error generated.
同样,定义一个参数类型为抽象类的函数也是非法的:
void f(A a) {} // illegal
确实,clang
是这样提示的:
wat.cc:5:10: error: parameter type 'A' is an abstract class
void f(A a) {}
^
wat.cc:2:16: note: unimplemented pure virtual method 'm' in 'A'
virtual void m() = 0;
^
1 error generated.
另一方面,定义一个类型为指向抽象类值的指针的变量当然是合法的:
A * a_ptr; // legal
即使该类从未定义任何基类,A *
类型至少有一个值,nullptr
,因此始终可以使用这样的变量以类型正确的方式,即使它可能不是很有用,除非 A
在某些时候获得一些具体的子类:
a_ptr = nullptr; // legal
据推测,这个推理适用于任何指针类型。
同样,定义一个接受参数的函数是合法的,该参数的类型是指向抽象类的值的指针:
void f(A * a) {} // legal
同样,定义一个接受参数的函数是合法的,该参数的类型是指向函数的指针,该函数的参数类型是指向抽象类的值的指针:
void f(void (* g)(A *)) {} // legal
这两个函数当然可以合法调用:
f(nullptr); // legal
据推测,函数参数的具体类型与类型的正确性无关,只要是指针类型即可。在任何一种情况下,对 f
的调用都应该是合法的。就类型理论而言,格式良好的指针类型始终是合法的,并且 nullptr
始终存在于其中。根据这个推理,这个定义应该被假定为合法的:
void f(void (* g)(A)) {}
f
是一个接受参数的函数,该参数的类型是指向函数的指针,该函数接受的参数类型是抽象类 A 的值。
事实上,该参数的唯一可能值是 nullptr
,因为没有实际函数可以采用类型为抽象类的参数。
这符合 C++ 标准吗?
Clang 提示:
wat.cc:5:20: error: parameter type 'A' is an abstract class
void f(void (* g)(A)) {}
^
wat.cc:2:16: note: unimplemented pure virtual method 'm' in 'A'
virtual void m() = 0;
^
1 error generated.
GCC 没有。
更新:这个问题回答正确,但问题本身在声明 Clang 接受该功能时是错误的。 GCC 和 Clang 都会在这段代码中产生类似的错误。但是,Clang 接受这样的函数如果它们是成员函数。这有效:
#include <iostream>
struct A {
virtual ~A() = 0;
};
struct B {
void f(void (*g)(A)) {
std::cout << "Works!" << std::endl;
}
};
int main() {
B().f(nullptr);
return 0;
}
不过,这似乎只是 Clang 中的一个错误。根据接受的答案中引用的标准部分中的语言,应该拒绝此代码。
最佳答案
[class.abstract]/3 说:
An abstract class shall not be used as a parameter type
关于c++ - 指向采用抽象参数的函数的指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30969209/