在我的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()
。请详细说明一下。一旦在'A类'中删除了虚拟关键字,就不会再发生这种情况了。
答案 0 :(得分:7)
一旦声明虚函数在所有派生类中都是虚拟的(无论你是否明确指定它)。因此func()在A,B和C类中是虚拟的。
答案 1 :(得分:3)
有关基础知识,请阅读C++ FAQ Lite on Virtual Functions。
虚函数允许派生类替换基类提供的实现。只要有问题的对象实际上是派生类,编译器就会确保始终调用替换,即使对象是由基指针而不是派生指针访问的。这允许在派生类中替换基类中的算法,即使用户不知道派生类。
答案 2 :(得分:1)
语句应该调用B :: func()
由于指针指向类C
的对象,它将调用类C
中的函数。
虚函数导致run time binding,这意味着要调用的函数将根据指针指向的对象而不是在编译时声明的指针类型来决定。
答案 3 :(得分:1)
这是多态性的本质。 main函数不需要知道ptr
实际指向类C
的对象,它只需要知道可用接口至少是类{{1}中定义的接口(这就是你将其声明为B
的原因,如果您需要特定于B *ptr
的函数,则必须执行C
)。
当你说这个函数在B中是虚拟的时,意味着它可能被子类重载,并且编译器会生成寻找这个备用实现的代码。在这种情况下,它在C *ptr
中找到它(实际的细节可能因编译器而异,但大多数编译器让对象带有一个表,即所谓的虚拟表,将C
映射到具体实现),并调用一个。
如果没有虚拟关键字,这会告诉编译器没有替代实现,并直接将其硬链接到B实现。
答案 4 :(得分: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;
}