以下代码中的虚函数如何工作

时间:2018-09-11 05:23:28

标签: c++

#include <stdio.h>
#include <string.h>
using namespace std;

class Base {
public: 
    virtual void gogo(float a){
        printf(" Base :: gogo (int) \n");
    };

    virtual void gogo(char *p){
        printf(" Base :: gogo (int*) \n");
    };
};

class Derived : public Base{
public:
    virtual void gogo(char *p){
        printf(" Derived ::  (int*)");
    };
};

int main(){
    Derived obj;
    obj.gogo(4.2);
}

为什么代码给出错误。即使函数gogo存在于基类中。但是在调用它时会出错

3 个答案:

答案 0 :(得分:1)

关于您的第二个疑问,这就是virtual关键字的工作方式。它用于实现多态。

display1仅在基类A中实现。因此,当virtual不用于display时, obj.display1最终调用类display的{​​{1}}。但是,当A用于virtual时,它将调用类display的{​​{1}}。在这种情况下,类display的{​​{1}}已覆盖类B的{​​{1}}。

答案 1 :(得分:0)

情况:如果未将display()声明为虚拟: obj.display1()将调用A::display1(),因为它没有被类B覆盖。由于display1()不是虚拟的,因此不会检查动态函数解析(@virtual表)并最终调用A::display()

情况:如果display()被声明为虚拟: 对于“对display()的调用,将引用对象的虚拟表(obj:B类)作为函数地址,这将导致对B::display(的调用。

答案 2 :(得分:0)

这是C ++众所周知的 [需要引用] 的细微差别,与多重重载与继承的交互方式有关。

virtual排除在等式之外,因为此处无关紧要。继承的工作方式是通过 lookup 首先检查您拥有的类,然后检查基数(如果找不到匹配项)。

在此示例中,您具有三个独立的功能(即使它们都共享一个名称(ish)):Base::gogo(float)Base::gogo(char*)Derived::gogo(char*)。您希望编译器找到Base::gogo(float)。通过用gogo调用float,您可以期望它在gogo(float)中寻找Derived,然后在{{ 1}}然后成功。

但是,它会在gogo(float)中查找Base(忽略参数类型!),找到它,然后 then 检查该类中的所有重载 ,发现没有一个gogo失败了。就是这样。

我们说Derived“隐藏” float

但是,使用Derived::gogo(char*)声明很容易解决:

Base::gogo(float)

通过这种方式,我们实质上创建了一个using,其内容与#include <stdio.h> #include <string.h> using namespace std; class Base { public: virtual void gogo(float a){ printf(" Base :: gogo (int) \n"); }; virtual void gogo(char *p){ printf(" Base :: gogo (int*) \n"); }; }; class Derived : public Base{ public: using Base::gogo; // <--- Here! virtual void gogo(char *p){ printf(" Derived :: (int*)"); }; }; int main(){ Derived obj; obj.gogo(4.2); } 相同,而不必再次将其写出。认为这是一种强制继承。

是的,这有点奇怪。但是您会习惯的。

请注意,这与Derived::gogo(float)无关。