所有
当我在C ++中研究多态时,我在这里找到一个小例子:
#include <iostream>
using namespace std;
class Base{
public:
virtual void f(float x){cout<<"Base::f(float)"<<x<<endl;}
void g(float x){cout<<"Base::g(float)"<<x<<endl;}
void h(float x){cout<<"Base::h(float)"<<x<<endl;}
};
class Derived:public Base{
public:
virtual void f(float x){cout<<"Derived::f(float)"<<x<<endl;}
void g(int x){cout<<"Derived::g(int)"<<x<<endl;}
void h(float x){cout<<"Derived::h(float)"<<x<<endl;}
};
int main(void){
Derived d;
Base *pb=&d;
Derived *pd=&d;
//Good:behavior depends solely on type of the object
pb->f(3.14f); //Derived::f(float)3.14
pd->f(3.14f); //Derived::f(float)3.14
//Bad:behavior depends on type of the pointer
pb->g(3.14f); //Base::g(float)3.14
pd->g(3.14f); //Derived::g(int)3(surprise!)
//Bad:behavior depends on type of the pointer
pb->h(3.14f); //Base::h(float)3.14(surprise!)
pd->h(3.14f); //Derived::h(float)3.14
return 0;
}
在研究虚函数之后,我想我已经了解了多态的工作原理,但是在这段代码中还有一些问题,我不想打扰别人解释这段代码是如何工作的,我只需要有人能给我看详细在Derived类中(不需要太多细节,只显示在Vtable中安排的方法函数指针(或索引)和那些不是虚拟继承的结构)。
从pb-> h(3.14f); //Base::h(float)3.14(surprise!) 我想应该有几个vtables,我是对的吗?
谢谢!
答案 0 :(得分:2)
您的代码中只有一个多态(virtual
)成员函数签名:f(float)
。其他三个函数g(float)
,g(int)
和h(float)
不是虚拟的。由于您的“(惊喜!)”评论是在调用g()
和h()
之后发生的,我猜您会惊讶于这些函数不是多态的,或者您实际上对此行为感到惊讶非多态函数。
如果您对g()
和h()
不具有多态性感到惊讶,请认识到virtual
位于每个多态函数之前。如果函数未声明virtual
,则只有与基类中的虚函数具有相同的签名时,它才是多态的(这也意味着virtual
中的Derived
是多余的,但我个人觉得virtual
这种多余的使用是好的风格。由于virtual
仅出现在f(float)
之前,因此只有f(float)
会是多态的。
由于h()
不是多态的,因此通过基指针调用h()
调用h()
的基本版本并不奇怪。
关于g()
,派生类中的名称会隐藏基类中的任何相应名称,除非通过using
声明返回。这就是pd->g(3.14f)
调用Derived::g(int)
的原因,即使Base::g(float)
是更好的匹配。 Base::g
不可见。如果您将using Base::g;
放在Derived类中,它将调用g()
的float版本。 (请注意virtual
这里g()
没有区别,因为g(int)
和g(float)
是不同的功能签名 - 没有办法覆盖另一个。)
HTH