c++ - 指向采用抽象参数的函数的指针

标签 c++ abstract-class function-pointers

让 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/

相关文章:

java - 如何在 Java 中的 Eclipse 中自动创建抽象类的子类?

rust - 特征可以作为 Fn 引用或闭包传递吗

有人可以解释这个函数指针语法吗?

c++ - Makefile 不使用包含/库路径?

c++ - 如何声明一个 std::array of structs initialized inline with different values

Python设计模式: class that returns different objects depending on parameters

python - 具有抽象方法和属性的继承

c - 为什么这个简单的 Linux C 程序在运行时加载 .so 会崩溃?

c++ - 读取 Windows 注册表时顺序是否重要?

c++ - GetQueuedCompletionStatus 过早退出(或者我认为)