函数指针和虚函数

时间:2011-08-20 05:05:15

标签: c++ polymorphism

我想我的问题应该是愚蠢的,但我确实从未见过声明为虚拟的函数指针。是否有一个原因?

编辑:

我应该说:它指向的功能是否可能被指定为虚拟?

3 个答案:

答案 0 :(得分:5)

嗯,是的(和没有)。

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

为了指向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::foo调用b,而第二个将为对象D::foo调用d,即使我们在两种情况下都使用相同的指针值。这在许多应用程序中实际上是有意义的。

然而,在某些低级别的情况下,拥有一个与特定版本的虚函数紧密相连的指针会很有用。即当我们做

时,有一个指针可以为B::foo对象B的子对象调用d会很好
(d.*pfoo)();

为了实现这一点,我们需要能够指定是否要提前(在初始化时)或延迟(在调用时)绑定它。不幸的是,C ++语言没有提供这样的功能。

答案 1 :(得分:2)

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

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

鉴于上面两个明显不同,函数指针为虚拟的想法完全没有意义。

它指向的功能是否指定为虚拟?
正如我之前提到的,函数指针只存储函数的地址。它只是一个type。例如:

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

在上面的例子中:
iint *的一种类型。同样,
ptr是一种类型,它可以存储函数的地址,该函数不带参数并且不返回参数。

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

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

答案 2 :(得分:1)

虚拟性是成员函数的属性。如果您有指向虚拟成员函数的指针,则会自动进行虚拟调用。常规函数不能是虚函数,因此虚函数指针没有意义。在任何一种情况下都没有必要将函数指针设为虚拟,因为它指向的函数是计数的。