#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
存在于基类中。但是在调用它时会出错
答案 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)
无关。