函数指针和虚函数

function pointer and virtual function

本文关键字:函数 指针      更新时间:2023-10-16

我想我的问题应该是愚蠢的,但这是真的,我从来没有见过一个函数指针被声明为虚拟。这有什么原因吗?

编辑:

我应该说:它所指向的函数是否可能被指定为虚函数?

嗯,是(也不是)。

普通函数指针不能指向非静态成员函数。它们只能指向独立的函数,这就是为什么对于普通的函数指针来说,函数的虚拟性甚至不会出现在图中。

为了在c++中指向成员函数,你需要一个特殊类型的指针:具有指向成员函数类型的指针。这种类型的指针既可以指向非虚成员函数,也可以指向虚成员函数。如果要指向虚成员函数,则不需要采取特殊步骤。例如

struct B { 
  virtual void foo() {} 
  void bar() {} 
};
...
B b;
void (B::*pfunc)(); // declare a pointer to a member function
pfunc = &B::foo; // make it point to `B::foo`
(b.*pfunc)(); // calls `B::foo` for object `b`
pfunc = &B::bar; // make it point to `B::bar`
(b.*pfunc)(); // calls `B::bar` for object `b`

然而,当您创建这样的指针指向虚成员函数时,您必须记住,它并不真正绑定到类层次结构中该函数的特定版本。关于要调用的特定函数的决定是在调用时做出的。例如

// given the above `B`
struct D : B { 
  virtual void foo() {} 
};
...
void (B::*pfoo)(); // declare a pointer to a member function
pfoo = &B::foo; // and make it point to `B::foo`

在上面的例子中,我们让指针pfoo指向B::foo。还是我们?实际上,指针并没有硬链接到B::foo。这两个调用

B b;
D d;
(b.*pfoo)();
(d.*pfoo)();

将调用两个不同的函数。第一个将为对象b调用B::foo,而第二个将为对象d调用D::foo,尽管我们在两种情况下使用了相同的指针值。这在许多应用程序中都是有意义的。

然而,在一些低级的情况下,将指针硬绑定到虚函数的特定版本是有用的。也就是说,如果有一个指针可以在执行

操作时调用d对象的B子对象的B::foo
(d.*pfoo)();

要实现这一点,我们需要能够指定是想要早绑定(在初始化时)还是晚绑定(在调用时)。不幸的是,c++语言没有提供这样的功能。

函数指针就是指向函数的指针。它只是存储函数的地址,就像任何指向type的指针存储类型的地址一样。

关键字virtual通过动态调度实现多态行为(基类和派生类的函数之间)。

考虑到上述两者明显不同,函数指针为虚指针的想法根本没有意义。

它所指向的函数是否被指定为virtual ?
正如我之前提到的,函数指针只是存储函数的地址。这只是一个type。例如:

int *i = NULL;
void doSomething();
typedef void(*ptr)() = NULL;
ptr = &doSomething();

在上面的例子中:
iint *的一种。类似地,
ptr是一个存储不带参数也不返回参数的函数地址的类型。

所以,是的,从根本上说,你可以使函数指针指向的函数为虚函数,就像你可以通过在类中声明特定函数为虚函数来使任何函数为虚函数一样。

作为类型的函数指针可以指向具有该原型的任何函数,而将函数声明为虚函数意味着在特定的函数上启用动态分派,正如您所看到的,两者是不相同的。

虚性是成员函数的一个属性。如果你有一个指向虚成员函数的指针,那么将自动进行虚调用。常规函数不能是虚函数,因此虚函数指针没有意义。在这两种情况下,将函数指针设置为虚指针是没有意义的,因为它所指向的函数才算数。