【概念】
a) 作用域。
作用域有大小之分。比如全局作用域大于局部作用域,这个很显然。要强调的是另一点:基类作用域大于派生类作用域。可能有人会有疑问,这两个作用域看不见摸不到,怎么知道大小?但是其实仔细想想,这很符合现实世界的面向对象模型:鱼的作用域显然要比金鱼大,交通工具的作用域肯定要比飞机大。如果你实在理解不了,那你还是就这么记住吧。
b) 名字查找。
请注意,这里的名字仅仅是指函数的名字,而不是原型!名字相同,查找即成功。这是个跟作用域密切相关的概念。名字查找符合以下的过程:
1.根据对象,指针,引用的静态版本决定哪一个函数被调用。
2.到相应的类中查找,如果没有找到,则到该类的直接基类中查找,按此过程下去都没找到,报错。
3.找到,做原型检查,看调用是否正确。
4.正确,判断是否动态绑定,调用相应版本。
2.到相应的类中查找,如果没有找到,则到该类的直接基类中查找,按此过程下去都没找到,报错。
3.找到,做原型检查,看调用是否正确。
4.正确,判断是否动态绑定,调用相应版本。
这个过程概括就是:先静态,后动态;作用域从小至大。
======================================================
[举例]
下面举几个例子来说明这种情况。
(1)下面这个例子说明了名字查找只根据静态类型查找(即使是指针调用,也只看指针的静态类型)。也可以从另一个角度理解这个问题:
“虚函数必须在基类和派生类中拥有同一原型”。 所以,Derived类中的func()其实已经不是虚函数了,所以其实不能提供多态的性质。当然,Derived类中仍然有虚函数指针(Derived类对象的size都是4),其中存的是base::func()。
#include <iostream>
using namespace std;
class Base
{
public:
virtual void func(double i){ cout<<"in base\n"; }
};
class Derived : public Base
{
public:
void func(){ cout<<"in derived\n"; }
};
int main(void)
{
Base b;
Derived d;
Base *pb = &d;
Derived *pd = &d;
b.func(3.14);
//b.func(); //compile error
//d.func(3.14); //compile error
d.func();
pb->func(3.14);
//pb->func(); //compile error : can't find func() in Base
//pd->func(3.14); //compile error : can't find func(double) in Derived
pd->func();
}
using namespace std;
class Base
{
public:
virtual void func(double i){ cout<<"in base\n"; }
};
class Derived : public Base
{
public:
void func(){ cout<<"in derived\n"; }
};
int main(void)
{
Base b;
Derived d;
Base *pb = &d;
Derived *pd = &d;
b.func(3.14);
//b.func(); //compile error
//d.func(3.14); //compile error
d.func();
pb->func(3.14);
//pb->func(); //compile error : can't find func() in Base
//pd->func(3.14); //compile error : can't find func(double) in Derived
pd->func();
}
(2)下面是《C++ Primer》书中的经典例子。
class Base
{
public:
virtual int fcn();
};
class Derived1 : public Base
{
public:
//hides Base::fcn(), this fcn(int) is not virtual
int fcn(int);
//Derived1 inherits definition of Base::fcn()
};
class Derived2 : public Derived1
{
public:
int fcn(int);//nonvirtual function hides Derived1::fcn(int)
int fcn();//redefine virtual Base::fcn()
};
{
public:
virtual int fcn();
};
class Derived1 : public Base
{
public:
//hides Base::fcn(), this fcn(int) is not virtual
int fcn(int);
//Derived1 inherits definition of Base::fcn()
};
class Derived2 : public Derived1
{
public:
int fcn(int);//nonvirtual function hides Derived1::fcn(int)
int fcn();//redefine virtual Base::fcn()
};
请读者自行理解。