#include <iostream>
using namespace std;
class Base{
public:
virtual int call()
{
int a = 2;
cout << "Base " << a << endl;
return a;
}
};
class D1:public Base{
public:
int call(int a)
{
cout << "D1 " << a << endl;
return a;
}
};
class D2:public D1{
public:
int call()
{
int a = 3;
cout << "D2 " << a << endl;
return a;
}
int call(int a)
{
cout << "D2 " << a << endl;
return a;
}
};
int main()
{
D1 d1;
d1.call();// error: no matching function for call to 'D1::call()',why?
D2 d2;
d2.call();//ok
Base bobj; D1 d1obj; D2 d2obj;
Base *bp1 = &bobj, *bp2 = &d1obj, *bp3 = &d2obj;
bp1->call(); // ok: virtual call, will call Base::call at run time
bp2->call(); // ok: virtual call, will call Base::call at run time
bp3->call(); // ok: virtual call, will call D2::call at run time
int i;
cin >> i;
}
参考下面空白理解:
关键概念:名字查找与继承
Understanding how function calls are resolved is crucial to understanding inheritance hierarchies in C++. The following four steps are followed:
理解 C++ 中继承层次的关键在于理解如何确定函数调用。确定函数调用遵循以下四个步骤:
1.
|
Start by determining the static type of the object, reference, or pointer through which the function is called. 首先确定进行函数调用的对象、引用或指针的静态类型。 |
2.
|
Look for the function in that class. If it is not found, look in the immediate base class and continue up the chain of classes until either the function is found or the last class is searched. If the name is not found in the class or its enclosing base classes, then the call is in error. 在该类中查找函数,如果找不到,就在直接基类中查找,如此循着类的继承链往上找,直到找到该函数或者查找完最后一个类。如果不能在类或其相关基类中找到该名字,则调用是错误的。 |
3.
|
Once the name is found, do normal type-checking to see if this call is legal given the definition that was found. 一旦找到了该名字,就进行常规类型检查,查看如果给定找到的定义,该函数调用是否合法。 |
4.
|
Assuming the call is legal, the compiler generates code. If the function is virtual and the call is through a reference or pointer, then the compiler generates code to determine which version to run based on the dynamic type of the object. Otherwise, the compiler generates code to call the function directly. 假定函数调用合法,编译器就生成代码。如果函数是虚函数且通过引用或指针调用,则编译器生成代码以确定根据对象的动态类型运行哪个函数版本,否则,编译器生成代码直接调用函数。 |
关键点:这个错误发生在编译时,d1调用的call编译器在编译时会在d1的作用域内查找,结果被编译器找到了,所以它就不会再网上去查找call了,但此处的call(int),所以调用不匹配就报错了。派生类要么重定义所有重载版本,要么一个也不重定义。