多态:
第一部分:静态多态:
1. 函数重载:函数名称相同,参数个数不一致或者参数类型不一致,并且返回值必须相同的函数为重载函数。
2. 运算符重载:也是通过函数重载来实现。当重载运算符两边或者一边出现重载函数里面的数据类型(比如类对象等),则系统知道需要调用重载运算符相对应的重载函数,并且严格按照参数类型进行数据类型匹配。
运算符重载有三种类型:类成员函数,类友元函数,普函数。
普通函数:其中普通函数极少使用,一般无需访问类的私有成员时,可以使用。
成员函数:如果将运算符重载函数作为成员函数,必须要求运算表达式第一个参数(即运算符左侧的操作数)是一个类对象,而且与运算符函数中的第一个参数类型相同。---------这样只需写一个函数的参数(运算符右侧的操作数),第一个参数通过this指针(所指对象)传入运算符重载成员函数进行运算。(只有类对象才有this指针,所以运算符左边操作数必须是类对象,并且运算符重载函数返回值与该对象同类型,运算结果才有意义。)
友元函数:如果运算符左侧的操作数为标准类型(如int)或是一个非本类对象,则运算符重载函数只能作为友元函数(前提都是需要访问私有成员)。而不能作为成员函数。---------(无法通过this指针传入类对象,必须有两个参数,跟操作数一致,并且无法使用交换律,除非再定义一个交换参数类型的运算符重载函数,其实也就是参数严格一致)
第二部分:动态多态:
1. 同名覆盖:如果派生类中有跟基类中一模一样的函数,则派生类对象(非指针和非引用)只能调用派生类中的同名函数,这就是同名覆盖。
解决方式1:使用基类类型指针指向派生类对象,即可调用派生类中的基类部分同名函数。
2. 指针调用:对于第1点解决方式1的情况,一旦使用了基类指针指向了派生类,则无法使用此指针调用派生类同名函数
解决方式2:将基类同名函数声明为虚函数。因为对于使用了虚函数的类对象,指针调用对象的虚函数,一定会按照指针所指向的对象来调用。--------即:基类类型指针所指对象为派生类,则调用的所有同名函数(此同名函数必须在基类中使用virtual声明,否则无效)均只会是派生类同名函数;基类类型指针所指对象为基类,无需讨论,肯定是基类里面的内容,与是否是虚函数无关。
3. 虚析构函数:
对于第1点解决方式的情况,一旦使用了基类类型指针指向了派生类,而此时构造函数和析构函数又有动态内存的分配和撤销,则派生类的析构函数无法使用,会造成内存泄漏。
解决方式3:将基类析构函数指明为虚析构函数。即可在第1点解决方式1的前提下正确执行派生类析构函数。一旦指明基类析构函数为虚析构函数,则其所有派生类析构函数全部自动成为虚析构函数。
注意:设计类时,基类的析构函数一定要设计为虚析构函数,而构造函数不能声明为虚函数。
指针调用/对象调用:
按照指针调用虚函数:虚函数(仅需基类中声明就行了)主要用于指针调用虚函数的时候,虚函数按照指针所指对象来调用。------即:如果基类类型指针所指对象为派生类,则会调用派生类的函数。析构函数也会先调用派生类中的。
按照对象调用虚函数:跟普通函数一致
4. 纯虚函数:
有纯虚函数的类称为抽象基类。
目的:将其定义在抽象基类中,用于被派生类继承,并且重载,从而提供一个统一的接口。(纯虚基类和虚基类都可以被正确地继承)
编程实现:运算符重载
#include<iostream>
using namespace std;
class Ccomplex{
public:
int x;
int y;
Ccomplex(){
x = 0;
y = 0;
}
void setNum(int a,int b){
x = a;
y = b;
}
void showComplex(){
if(y < 0){
cout<<x<<y<<"i"<<endl;
}else if(y > 0){
cout<<x<<"+"<<y<<"i"<<endl;
}else{
cout<<x<<endl;
}
}
Ccomplex operator++(){
++x;
++y;
return *this;
}
Ccomplex operator++(int){
x++;
y++;
return *this;
}
/*Ccomplex operator+(const Ccomplex &right){ //类似这种写法都是错误的,虽然结果正确,但是却更改了左操作数的值,
//必须定义临时对象才不会改变操作数
x += right.x;
y += right.y;
return *this;
}*/
Ccomplex operator+(const Ccomplex &right){ //因为实际调用肯定会出现另外得赋值符,所以必须重新定义临时对象,才能保证不改变左右操作数:调用时为:c = a + b;
Ccomplex tmp;
tmp.x = x + right.x;
tmp.y = y + right.y;
return tmp;
}
Ccomplex operator+=(const Ccomplex &right){ //成员函数形式实现符合运算符重载,即:a=a + b;成员函数只允许出现一个操作数
x += right.x;
y += right.y;
return *this;
}
friend Ccomplex operator-=(Ccomplex &left, const Ccomplex &right){ //友元函数形式实现复合运算符重载,函数调用不出现另外的
//赋值符,即a=a - b; 特别注意,这里左操作数必须是引用,否则无法实现a=a-b;的功能
left.x -= right.x;
left.y -= right.y;
return left;
}
friend ostream& operator<<(ostream& left, Ccomplex &right){ //左操作数必须为输出流,如cout
if(right.y > 0){
left <<right.x<<"+"<<right.y<<"i"<<endl;
}else if(right.y < 0){
left <<right.x<<right.y<<"i"<<endl;
}else{
left <<right.x<<endl;
}
return left;
}
friend istream& operator >> (istream& left, Ccomplex &right){ //做操作数必须为输入流,如cin
cout<<"input Ccomplex.x"<<endl;
left>>right.x;
cout<<"input Ccomplex.y"<<endl;
left>>right.y;
return left;
}
};
class Ccomplex_array{
public:
Ccomplex& operator[](int i){ //下标运算符重载
return com[i];
}
private:
Ccomplex com[3];
};
int main(){
int i;
cout<<"1-------------------------"<<endl;
Ccomplex test1;
test1.setNum(11,22);
cout<<"test1= ";
test1.showComplex();
cout<<"++test1,test1= ";
(++test1).showComplex();
cout<<"2*************************"<<endl;
Ccomplex test2;
test2.setNum(33,44);
cout<<"test2= ";
test2.showComplex();
cout<<"(test2++),test2= ";
(test2++).showComplex();
cout<<"3-------------------------"<<endl;
Ccomplex test3;
test3 = test1 + test2;
cout<<"test3 = test1 + test2,test3 = ";
test3.showComplex();
cout<<"4*************************"<<endl;
Ccomplex test4;
test4 = test1 += test3; //这里test1变化了,test4的值跟test1一致,+=跟=运算符优先级为同级,右结合
cout<<"test1 += test3,test1= ";
test1.showComplex();
cout<<"test4: ";
test4.showComplex();//这里,test4的值等于test1+test3
cout<<"5--------------------------"<<endl;
test4 = test2 -= test3;// 这里,test2变化了,相当于a -= b; (a,b为常数)
cout<<"test2 -= test3,test2= ";
test2.showComplex();
cout<<"test4: ";
test4.showComplex();
cout<<"6**************************"<<endl;
Ccomplex_array com_array;
for(i=0;i<3;i++){
com_array[i].x = i+1;
com_array[i].y = i+2;
}
for(i=0;i<3;i++){
com_array[i].showComplex();
}
cout<<"7------------------------"<<endl;
Ccomplex test5;
cin>>test5; //左边cin为输入流,符合重载左操作数要求
cout<<test5; //右边cout为输出流,符合重载操作数要求
return 0;
}