6.C++:关于C++多态基本知识

多态:

第一部分:静态多态:

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;
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值