1. 函数重载(overloading)与静态联编(static binding)
函数重载(overloading)指的是,允许多个不同函数使用同一个函数名,但要求这些同名函数具有不同的参数表。
. 参数表中的参数个数不同;
. 参数表中对应的参数类型不同;
. 参数表中不同类型参数的次序不同。
例:
intabs(int n){
return (n<0?-n:n);
}
floatabs(floatn) {
if (f<0) f=-f;
return f;
}
系统对函数重载这种多态性的分辨与处理,是在编译阶段完成的 -- 静态联编(static binding)。
2 函数超载(overriding)、虚函数(virtual function)及动态联编(dynamic binding)
(1) 函数超载(overriding)
. 仅在基类与其派生类的范围内实现;
. 允许多个不同函数使用完全相同的函数名、函数参数表以及函数返回类型;
(2)虚函数(virtual function)
. 在定义某一基类(或其派生类)时,若将其中的某一函数成员的属性说明为virtual,则称该函数为虚函数(virtual function)。
. 虚函数的使用与函数超载密切相关。若基类中某函数被说明为虚函数,则意味着其派生类中也要用到与该函数同名、同参数表、同返回类型、但函数(实现)体不同的这同一个所谓的超载函数。
class graphelem {
protected:
int color;
public:
graphelem(int col) {
color=col;
}
virtualvoid draw(){ ... };
//虚函数draw,每一个类都要“draw”出属于它的类对象图形
};
classline:publicgraphelem{
public:
virtual void draw(){ ... }; //虚函数draw,负责画出“line”
...
};
classcircle:publicgraphelem{
public:
virtual void draw(){ ... }; //虚函数draw,负责画出“circle”
...
};
classtriangle:publicgraphelem{
public:
virtual void draw(){ ... }; //虚函数draw,负责画出“triangle”
...
};
(3)动态联编(dynamic binding)
与虚函数以及程序中使用指向基类的指针(变量)密切相关。
注意:C++规定,基类指针可以指向其派生类的对象(也即,可将派生类对象的地址赋给其基类指针变量),但反过来不可以。这一点正是函数超载及虚函数用法的基础。
例1.建立上述类line、类circle以及类triangle的类对象,而后调用它们各自的draw函数“画出”它们。
方法1:直接通过类对象(由类对象可以唯一确定要调用哪一个类的draw函数)
line ln1; circle cir1; triangle tri1;
ln1.draw();
cir1.draw();
tri1.draw();
方法2:使用指向基类的指针(动态联编,要靠执行程序时其基类指针的“动态”取值来确定调用哪一个类的draw函数)
graphelem *pObj;
line ln1; circle cir1; triangle tri1;
pObj=&lin1; pObj->draw();
pObj=&cir1; pObj->draw();
pObj=&tri1; pObj->draw();
例2. 假设inte_algo为基类,其中说明了一个虚函数integrate,并在其三个派生类中,也说明了该虚函数integrate(使用不同方法计算定积分)。
那么,可使用函数integrateFunc来实现调用不同虚函数integrate的目的:
void integrateFunc(inte_algo * p){
//基类指针p可指向任一派生类的对象
p->integrate();
//调用的将是不同派生类的integrate函数
}
主调函数处使用:
integrateFunc( <某派生类的类对象地址> );
在编译阶段,系统无法确定究竟要调用哪一个派生类的integrate。此种情况下,将采用动态联编方式来处理:在运行阶段,通过p指针的当前值,去动态地确定对象所属类,而后找到对应虚函数。
3 纯虚函数与抽象基类
如果不准备在基类的虚函数中做任何事情,则可使用如下的格式将该虚函数说明成纯虚函数:
virtual<函数原型>=0;
纯虚函数不能被直接调用,它只为其派生类的各虚函数规定了一个一致的“原型规格”(该虚函数的实现将在它的派生类中给出)。
含有纯虚函数的基类称为抽象基类。注意,不可使用抽象基类来说明并创建它自己的对象,只有在创建其派生类对象时,才有抽象基类自身的实例伴随而生。
实际上,抽象基类是其各派生类之共同点的一个抽象综合,通过它,再“加上”各派生类的特有成员以及对基类中那一纯虚函数的具体实现,方可构成一个具体的实用类型。
另外:如果一个抽象基类的派生类中没有定义基类中的那一纯虚函数、而只是继承了基类之纯虚函数的话,则这个派生类还是一个抽象基类(其中仍包含着继承而来的那一个纯虚函数)。