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 关键字,就不会再发生这种情况了。

4

5 回答 5

7

一旦声明了虚函数,在所有派生类中都是虚函数(无论您是否明确指定它)。所以 func() 在 A、B 和 C 类中是虚拟的。

于 2009-12-10T08:18:38.940 回答
3

对于基础知识,您应该阅读C++ FAQ Lite on Virtual Functions

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

于 2009-12-10T08:18:03.490 回答
1

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

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

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

于 2009-12-10T08:20:00.450 回答
1

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

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

如果没有 virtual 关键字,这会告诉编译器没有替代实现,并将其直接硬链接到 B 实现。

于 2009-12-10T08:20:49.710 回答
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;
}
于 2009-12-10T08:41:00.160 回答