每一个块都是一个作用域(块就是{}中间的)。
同样,每个类也是一个作用域。我们在这个作用域内定义函数和一些数据成员。对于类的派生类而言,它的作用域实际上是嵌套在基类中的。如图所示:
在你调用一个函数或者数据项的时候,它会首先在这个作用于内部去寻找,如果找不到便会在外部作用域去寻找,直到找到为止,如果实在没法找到,那么便会报错。
先举一个类似于类的栗子,如代码所示:
#include<iostream>
using namespace std;
int f1()
{
return 1;
}
int main()
{
int tmp = f1();
system("pause");
return 0;
}
这个程序是正确的main函数内部没有找到,去了全局作用域去找,找到了f1,在进行类型安全检查。大家注意看下面这个例子.
#include<iostream>
using namespace std;
int f1()
{
return 1;
}
int main()
{
char f1;
int tmp = f1();
system("pause");
return 0;
}
比较之前的例子,这里多了一个
char f1;
编译器报错,提示为: error C2064: 项不会计算为接受 0 个参数的函数。它竟然匹配到了char f1 上,并没有去匹配函数f1,这意味着编译器如果在当前作用域找到了该名字解析,那么它便不会再去寻找了。
类同样也适用这个规则:
1.派生类作用域嵌套在基类中,所以通过基类的静态类型是无法搜寻到派生类独有的一部分。
2.派生类作用域嵌套在基类中,所以派生类内部如果找不到该成员定义,那么它会去基类那个作用域内部去寻找。
举个栗子:
#include<iostream>
using namespace std;
class Base
{
public:
void f1() {
cout << "base's f1() has been called." << endl;
}
};
class Derive:public Base
{
public:
void f1(int) {
cout << "derive's f1(int) has been called." << endl;
}
};
int main()
{
Base b;
Derive d;
b.f1(); //True 调用基类
d.f1(0); //True 调用派生类
d.f1(); //False 解析错误
system("pause");
return 0;
}
最后的解析错误也是上面的原因。此时在派生类声明可以加一个
using Base::f1;
或者调用时加
d.Base::f1();
都可以解决这个问题。
虚函数为什么强制要求必须参数列表和const属性和返回值类型必须相同(除了特例,如返回值是基类引用或指针),如果你参数有差异的话,那么就不会实现多态性,因为派生类的参数不同,所以无法匹配.