C++中的虚函数

3

在我的C++程序中:

#include<iostream.h>

class A
{
    public:
    virtual void func()
    {
         cout<<"In A"<<endl;
    }
};

class B:public A
{
    public:
    void func()
    {
        cout<<"In B"<<endl;
    }
};

class C:public B
{
    public:
    void func()
    { 
        cout<<"In C"<<endl;
    }
};  

int main()
{
    B *ptr=new C;
    ptr->func();
}

这个语句应该调用B::func()函数。然而,却调用了C::func()函数。请解释一下。当在'class A'中移除virtual关键字时,就不会再发生这种情况。

5个回答

7
一旦声明为虚函数,它将在所有派生类中成为虚函数(无论您是否明确指定)。因此,在A、B和C类中,func()都是虚函数。

3

如果您想了解基本知识,可以阅读C++ FAQ Lite on Virtual Functions

虚函数允许派生类替换基类提供的实现。编译器确保只要对象实际上是派生类,即使通过基类指针而不是派生类指针访问对象,也始终调用替换函数。这允许在派生类中替换基类中的算法,即使用户不知道派生类的存在。


但是,我在B类中重新定义了func()函数,这不会削弱函数的虚拟性质吗? - Avik Banerjee
阅读常见问题解答 :) 如果您在基类中将一个方法声明为虚拟的,则不需要在任何派生类中放置“virtual”关键字 - 它仍然会是虚拟的。如果您使用不同的参数重载函数,则它将以非虚拟方式工作。 - Marcin Gil

1

语句应该调用B::func()

由于指针指向类C的对象,它会调用类C中的函数。

虚拟函数导致运行时绑定,这意味着要调用的函数将基于指针所指向的对象决定,而不是在编译时声明的指针类型。


1

这就是多态的本质。主函数不需要知道 ptr 实际上指向的是类 C 的对象,它只需要知道可用的接口至少是在类 B 中定义的(这就是为什么你将其声明为 B *ptr,如果你需要特定于 C 的函数,你必须使用 C *ptr)。

当你说函数在 B 中是虚拟的时,这意味着它可以被子类重载,并且编译器生成的代码会查找这个替代实现。在这种情况下,它在 C 中找到了它(实际细节可能因编译器而异,但大多数编译器让对象携带一个表,即所谓的虚拟表,将 func() 映射到特定的实现),并调用那个实现。

如果没有虚拟关键字,这告诉编译器不能有另一种实现,并将其硬链接到 B 实现直接。


0

如果你已经完成了:

B *obj = new B;

那么它将会调用B::func()。
为了实现您期望的功能,您应该删除C中func的新实现。
如果您使用虚函数,实际上就是在说我不知道我内部有什么类型的对象,只要它来自同一类对象的“家族”(在这里A是“家族”的“父亲”)。您所知道的是,“家族”的每个成员都必须为特定部分执行不同的工作。例如:

class Father
{
public:
  virtual void func() { cout << "I do stuff"; }
};
class Child : public Father
{
public:
  virtual void func() { cout << "I need to do something completely different"; }
};

int main()
{
  Father *f = new Father;
  f->func(); // output: I do stuff
  delete f;
  f = new Child;
  f->func(); // output: I need to do something completely different
  delete f;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接