同一个消息被不同对象接收时,产生不同的结果。即采用不同方法实现同一接口。
联编
使一个源程序经过编译,连接,成为可执行文件的过程
静态联编
在程序运行之前就完成的联编
系统在编译时就知道调用函数的全部信息
函数调用速度快,效率高
动态联编
在程序运行时才能完成的联编
知道程序运行时才能确定调用哪个函数
灵活性,问题抽象性和程序易维护性
赋值兼容
在需要基类对象的任何地方,都可以使用共有派生类的对象来代替
Base b;Derived d; b=d;
Derived d; Base &br = d;
Derived d; Base *bptr = &d;
Derived *dptr; Base *bptr = dptr;
((Derived*)bpt)->print2(); //基类指针要强制转换才能访问派生类熟悉
虚函数
冠以关键字virtual的成员函数
如果在基类中定义了一个虚函数,该虚函数可以在它的一个或多个派生类中重载,不用冠以virtual也自动成为虚函数
运行时的多态(动态联编支持)
通过继承和虚函数来实现
->在基类,定义派生类所拥有的通用接口
->在派生类,定义具体的实现方法
->实现运行时的多态性
在程序中使用基类指针调用,知道程序运行时,系统才能确定调用哪一个函数
class base{
public;
virtual void show();
};
class de:public base
{
void show()
{
cout<<”de”<<endl;
}
};
eg:
class base{
protected:
double x,y;
public:
base(double a, double b)
{
x = a;
y = b;
}
~base();
virtual void show()
{
cout<<”base show”<<endl;
}
};
class de1:public base{
public:
de1(double a, double b):base(a,b)
{}
~de1();
void show()
{
cout<<”de1 show”<<endl;
}
};
class de2:public base{
public:
de2(double a, double b):base(a,b)
{}
~de2();
void show()
{
cout<<”de2 show”<<endl;
}
};
main()
{
base* pb;
de1 d1(22,22);
de2 d2(22,22);
pb = &d1;
pb->show();
pb = &d2;
pb->show();
return ();
}
纯虚函数(有一个或多个虚函数的类叫抽象类,抽象类不能实例化)
virtual type func_name(参数表)=0;
基类仅表示一种抽象的概念,并不与具体的事物相联系。
这样的虚函数在基类中没有定义
#include<iostream>
class shape(){
public:
virtual void draw()=0;
virtual void rotateshape()=0;
};
class circle():public shape{
int radius
public:
circle(int r)
{
radius = r;
}
void draw()
{
cout<<”draw”<<2*3.14*radius<<endl;
}
};
class rectangle():public shape{
protected:
double x,y;
public:
rectangle(double a, double b)
{x=a;y=b;}
void draw()
{
cout<<”draw”<<x*y<<endl;
}
};
float total(shape * arr[], int len)
{
double total = 0.0;
for (int i=0; i <n; i++)
{
total+=arr[i]->length();
}
return total;
}
main()
{
shape* arr[5];
circle c1(2,2);
arr[0] = &c1;
...
total(arr,5);
return 0;
}
编译时的多态(静态联编支持)
通过函数重载和运算符重载来实现
确定所调用函数的方式
参数匹配
支配原则
类名限定
运算符重载
运算符重载是通过创建运算符函数operator@()来实现的
运算符函数可以重载为:
类的成员函数
类的友员函数
eg
class A{
...
poublic:
A operator= (A &a);
friend A operator+ (A &a1, A &a2);
};
不允许重载的运算符:# . * ?:
自己不能创造运算符
成员运算符重载
函数的参数个数应比原有操作数个数少一个,还有一个是调用它的对象
class myclass{
public:
myclass operator+ (const myclass &a);
};
myclass myclass::operator+ (const myclass &a)
{
myclass temp;
temp.vaule1 = value1 + myclass.value1;
temp.vaule2 = value2 + myclass.value2;
return temp;
}
一元运算符重载
class myclass{
public:
myclass operator++();
myclass myclass::operator++()
{
++value1;
++value2;
return *this;
}
只能重载成成员函数不能重载为友员函数的运算符
= () [] ->
双目运算符一般重载为友员函数
单目运算符一般重载为成员函数
若运算符的操作需要修改类对象的状态选择成员运算符
若运算符的第一个操作数有隐式类型转换必须使用友员运算符