多态性与重载
多态性是面向对象程序设计的重要特征之一。多态是指一个名字有多种语义,或一个相同界面有多种实现;或是指发出同样的消息被不同类型的对象接受而导致完全不同的行为,即对象根据所接收到的消息做出相应的操作。
消息主要是指对类的成员函数的调用
不同的行为是指不同的实现
多态的实现:
- 函数重载
- 运算符重载
- 虚函数
函数重载
多态性的一种形式,它是指允许在相同的作用域内,相同的函数名对应着不同的实现。
函数重载的条件是要求函数参数的类型或个数有所不同。例如:
成员函数重载有三种方式:
在一个类中重载:参数的特征区分;例如:
show(int, char); show (char*, float);
在不同类中重载: 使用类作用域符::加以区分(不同类中重载,静态成员函数),例如:
Circle::show(); Point::show();
根据类对象加以区分(不同类中重载,不同成员函数),例如:
acirle.show()调用Circle::show()
apoint.show()调用Point::show()
基类的成员函数在派生类中重载:继承时再介绍。
例7.1 函数实现对象运算示例1:通过成员函数实现实现2个复数对象的加法运算
#include <iostream>
using namespace std;
class complex//复数类声明
{
public:
complex(double r=0.0,double i=0.0) //构造函数
{ real=r; imag=i;}void Show( ); //显示复数的值
complex add(complex &c);//复数与复数相加的函数
private:
double real;
double imag;
};
complex complex::add(complex &c2) //通过成员函数实现
{
complex t;
t.real=real+c2.real;
t.imag=imag+c2.imag;
return t;
}
void complex::Show()
{
cout<<"("<<real<<","<<imag<<")"<<endl;
}
int main() //主函数
{
complex z1(1.5,2.8),z2(-2.3,3.4),z3; //声明复数类的对象
z3=z1.add(z2);//成员函数调用
cout<<"z3=";
z3.Show();
return 0;
}
例7.2 函数实现对象运算示例2:通过友员函数实现2个复数对象的加法运算
#include <iostream>
using namespace std;
class complex //复数类声明
{
public: //外部接口
complex(double r=0.0,double i=0.0)
{real=r;imag=i;}//构造函数
friend complex add(complex &c1,complex &c2); //add2个复数友元函数
void Show(); //输出复数
private: //私有数据成员
double real; //复数实部
double imag; //复数虚部
};
complex add(complex &c1,complex &c2) //通过友元函数实现
{ complex t;
t.real=c1.real+c2.real;
t.imag=c1.imag+c2.imag;
return t;
}
void complex::Show()
{ cout<<"("<<real<<","<<imag<<")"<<endl;
}
int main() //主函数
{
complex z1(1.5,2.8),z2(-2.3,3.4),z3; //声明复数类的对象
z3=add(z1,z2);//友元函数调用
cout<<"z3=";
z3.Show();
return 0;
}
例7.3 函数实现对象运算示例3:通过成员函数重载实现2个复数对象的加法运算,以及1个复数对象和1个实数加法运算。
#include <iostream>
using namespace std;
class complex //复数类声明
{
public: //外部接口
complex(double r=0.0,double i=0.0){real=r;imag=i;}//构造函数
complex add(complex &c2); //2个复数对象加的成员函数
complex add(double e); //1个复数对象与1个实数加的成员函数
void Show(); //输出复数
private: //私有数据成员
double real; //复数实部
double imag; //复数虚部
};
void complex::Show()
{ cout<<"("<<real<<","<<imag<<")"<<endl;
}
complex complex::add(complex &c2) //通过成员函数实现
{ complex t;
t.real=real+c2.real;
t.imag=imag+c2.imag;
return t;
}
complex complex::add(double e) //通过成员函数实现
{ complex t;
t.real=real+e;
t.imag=imag;
return t;
}
int main() //主函数
{complex z1(1.5,2.8),z2(-2.3,3.4),z3,z4;
z3=z1.add(z2);//成员函数调用
z4=z3.add(5.6);
cout<<"z3=";
z3.Show();
cout<<"z4=";
z4.Show();
return 0;
}
例7.4 函数实现对象运算示例4:通过友员函数重载实现2个复数对象的加法运算,以及1个复数对象和1个实数加法运算。
#include <iostream>
using namespace std;
class complex //复数类声明
{
public: //外部接口
complex(double r=0.0,double i=0.0)//构造函数
{real=r;imag=i;}
friend complex add(complex &c1,complex &c2); //2个复数对象加友元函数
friend complex add(complex &c1,double e); //1个复数对象与1个实数加友元函数
void Show(); //输出复数
private: //私有数据成员
double real; //复数实部
double imag; //复数虚部
};
void complex::Show()
{ cout<<"("<<real<<","<<imag<<")"<<endl;
}
complex add(complex &c1,complex &c2) //通过友元函数实现
{ complex t;
t.real=c1.real+c2.real;
t.imag=c1.imag+c2.imag;
return t;
}
complex add(complex &c1,double e) //通过友元函数实现
{complex t;
t.real=c1.real+e;
t.imag=c1.imag;
return t;
}
int main() //主函数
{complex z1(1.5,2.8),z2(-2.3,3.4),z3,z4; z3=add(z1,z2);
z4=add(z3,5.6);
cout<<"z3=";
z3.Show();
cout<<"z4=";
z4.Show();
return 0;
}
小结
定义一种新的数据类型,就同时需要定义对这种类型数据的操作,最基本的方法就是定义一系列能够完成各种运算的函数。
- 利用成员函数实现运算,函数中可方便地访问复数对象中的私有成员。
- 利用友元函数实现运算,提供了一种非成员函数访问复数对象中的私有成员的手段。
- 利用函数重载这一种多态性形式,提供在相同的作用域内,相同的函数名对应着不同的实现。
运算符重载
运算符重载是对已有的运算符赋予多重含义。有两种方式:
- 重载为成员函数;
- 重载为友元函数
实质
- 必要性
C++中预定义的运算符其运算对象只能是基本数据类型,而不适用于用户自定义类型(如类) - 实现机制
将指定的运算表达式转化为对运算符函数的调用,运算对象转化为运算符函数的实参。
编译系统对重载运算符的选择,遵循函数重载的选择原则。
规则和限制
- 可以重载C++中除下列运算符外的所有运算符:
. * :: ?: sizeof - 只能重载C++语言中已有的运算符,不可臆造新的。
- 不改变原运算符的优先级和结合性。
- 不能改变操作数个数。
- 经重载的运算符,其操作数中至少应该有一个是自定义类型(即类)。
声明形式
函数类型 operator 运算符(形参)
{
body;
}
//作为成员函数重载时,第一操作数就是当前对象本身,因此它并不需要出现在参数表中。
- 重载为类成员函数时:
参数个数=原操作数个数-1 (后置++、–除外)参数个数=原操作数个数-1 (后置++、–除外) - 重载为友元函数时:
参数个=原操作数个数,且至少应该有一个自定义类型的形参。
由于友元函数不是任何类的成员函数,因此重载时必须在参数表中显式地给出所有的操作数。
双目运算符重载为成员函数(题9.1)
双目运算符 B
- 如果要重载 B 为类成员函数,使之能够实现:
表达式 oprd1 B oprd2,其中 oprd1为A 类对象,则 B 应被重载为 A 类的成员函数,形参类型应该是oprd2所属的类型。 - 经重载后,表达式 oprd1 B oprd2 相当于 oprd1.operator B(oprd2)。
即对象名 oprd1.函数名B(参数)的调用形式。
例7.5 将“+”运算重载为复数类的成员函数。
规则:实部和虚部分别相加。
操作数:两个操作数都是复数类的对象。
实现2个复数对象的加法运算,add成员函数与+运算符重载为成员函数。
#include <iostream>
using namespace std;
class complex //复数类声明
{
public: //外部接口
complex(double r=0.0,double i=0.0){real=r;imag=i;}//构造函数
complex add(complex &c2); //add成员函数
complex operator +(complex &c2); //+重载为成员函数
void Show(); //输出复数
private: //私有数据成员
double real; //复数实部
double imag; //复数虚部
};
complex complex::add(complex &c2) //通过成员函数实现
{ complex t;
t.real=real+c2.real;
t.imag=imag+c2.imag;
return t;
}
complex complex::operator +(complex &c2) //重载+运算符为成员函数
{ complex t;
t.real=real+c2.real;
t.imag=imag+c2.imag;
return t;//相当于return complex(t.real,t.imag);
}
void complex::Show()
{ cout<<"("<<real<<","<<imag<<")"<<endl;
}
int main() //主函数
{ complex z1(1.5,2.8),z2(-2.3,3.4),z3,z4 z3=z1.add(z2);//成员函数调用
cout<<"z3=";
z3.Show();
z4=z1+z2;//+运算符重载
cout<<"z4=";
z4.Show();
return 0;
}
双目运算符重载为友元函数(题9.2)
双目运算符 B
- 如果要重载 B 为友元函数,使之能够实现:
表达式 oprd1 B oprd2,其中 B 应被重载为 A 类的友元函数,形参类型应该是oprd1和oprd2所属的类型。 - 经重载后,表达式 oprd1 B oprd2 相当于 operator B(oprd1,oprd2 ),即函数名B(参数1,参数2)的调用形式。
例7.6 将“+”运算重载为复数类的成员函数。
规则:实部和虚部分别相加。
操作数:两个操作数都是复数类的对象。
实现2个复数对象的加法运算,add成员函数与+运算符重载为友元函数。
#include <iostream>
using namespace std;
class complex //复数类声明
{public: //外部接口
complex(double r=0.0,double i=0.0)//构造函数
{real=r;imag=i;}
friend complex add(complex &c1,complex &c2); //add2个复数友元函数
friend complex operator +(complex &c1,complex &c2); //+重载为友元函数
void Show(); //输出复数
private: //私有数据成员
double real; //复数实部
double imag; //复数虚部
};
complex add(complex &c1,complex &c2) //通过友元函数实现
{ complex t;
t.real=c1.real+c2.real;
t.imag=c1.imag+c2.imag;
return t;
}
complex operator +(complex &c1,complex &c2) //通过友元函数重载+运算符
{ complex t;
t.real=c1.real+c2.real;
t.imag=c1.imag+c2.imag;
return t;
}
void complex::Show()
{ cout<<"("<<real<<","<<imag<<")"<<endl;
}
int main() //主函数
{ complex z1(1.5,2.8),z2(-2.3,3.4),z3,z4 z3=add(z1,z2);//友元函数调用 cout<<"z3=";
z3.Show();
z4=z1+z2;//+运算符重载
cout<<"z4=";
z4.Show();
return 0;
}
单目运算符重载为成员函数(题9.3、9.7)
前置单目运算符 U
- 如果要重载 前置U 为类成员函数,使之能够实现表达式 U oprd,其中 oprd 为A类对象,则 U 应被重载为 A 类的成员函数,无形参。
- 经重载后,表达式 U oprd 相当于 oprd.operator U()
后置单目运算符U
- 如果要重载后置U为类成员函数,使之能够实现表达式 oprd U ,其中 oprd 为A类对象,U应被重载为 A 类的成员函数,且具有一个 int 类型形参。
- 经重载后,表达式 oprd U 相当于 oprd.operator U(0)
//参数0只是后置运算标志。
#include <iostream>
using namespace std;
class complex //复数类声明
{
public: //外部接口
complex(double r=0.0,double i=0.0){real=r;imag=i;}//构造函数
complex operator ++(); //重载前置++运算符为成员函数
complex operator ++(int); //重载后置++运算符为成员函数
void Show(); //输出复数
private: //私有数据成员
double real; //复数实部
double imag; //复数虚部
};
complex complex::operator ++() //重载成员函数实现
{ complex t;
t.real=real+1;
t.imag=imag+1;
real=real+1;
imag=imag+1;
return t;//相当于return complex(t.real,t.imag);
}
complex complex::operator ++(int) //重载成员函数实现
{ complex t;
t.real=real;
t.imag=imag;
real=real+1;
imag=imag+1;
return t;//相当于return complex(t.real,t.imag);
}
void complex::Show()
{
cout<<"("<<real<<","<<imag<<")"<<endl;
}
int main() //主函数
{complex z1(1.5,2.8),z2(1.5,2.8),z3,z4;
z3=++z1;//++前置运算符重载
cout<<"z3=";
z3.Show();
z4=z2++;//++后置运算符重载
cout<<"z4=";
z4.Show();
return 0;
}
单目运算符重载为友元函数(题9.4、9.8)
前置单目运算符 U
- 如果要重载 前置U 为类友元函数,使之能够实现表达式 U oprd,其中 U 应被重载为 A 类的成员函数,形参为oprd 所属类型。
- 经重载后,表达式 U oprd 相当于 operator U(oprd)
后置单目运算符U
- 如果要重载后置U为类友元函数,使之能够实现表达式 oprd U ,其中U应被重载为 A 类的成员函数,有2个形参,其中一个是oprd所属类型,另一个是int 类型形参,但不必写形参名。
- 经重载后,表达式 oprd U 相当于 operator U(oprd,0)。
//参数0只是后置运算标志
#include <iostream>
using namespace std;
class complex //复数类声明
{
public: //外部接口
complex(double r=0.0,double i=0.0){real=r;imag=i;}//构造函数
friend complex operator ++(complex &c); //重载前置++运算符为友元函数
friend complex operator ++(complex &c,int); //重载后置++运算符为友元函数
void Show(); //输出复数
private: //私有数据成员
double real; //复数实部
double imag; //复数虚部
};
complex operator ++(complex &c) //重载友元函数实现
{ complex t;
t.real=c.real+1;
t.imag=c.imag+1;
c.real=c.real+1;
c.imag=c.imag+1;
return t;//相当于return complex(t.real,t.imag);
}
complex operator ++(complex &c,int) //重载友元函数实现
{ complex t;
t.real=c.real;
t.imag=c.imag;
c.real=c.real+1;
c.imag=c.imag+1;
return t;//相当于return complex(t.real,t.imag);
}
void complex::Show()
{
cout<<"("<<real<<","<<imag<<")"<<endl;
}
int main() //主函数
{complex z1(1.5,2.8),z2(1.5,2.8),z3,z4;
z3=++z1;//++前置运算符重载
cout<<"z3=";
z3.Show();
z4=z2++;//++后置运算符重载
cout<<"z4=";
z4.Show();
return 0;
}