1. 程式人生 > >C++程式設計學習筆記 複習/拾遺 6

C++程式設計學習筆記 複習/拾遺 6

多型性與過載

多型性是面向物件程式設計的重要特徵之一。多型是指一個名字有多種語義,或一個相同介面有多種實現;或是指發出同樣的訊息被不同型別的物件接受而導致完全不同的行為,即物件根據所接收到的訊息做出相應的操作。

訊息主要是指對類的成員函式的呼叫
不同的行為是指不同的實現

多型的實現:

  1. 函式過載
  2. 運算子過載
  3. 虛擬函式

函式過載

多型性的一種形式,它是指允許在相同的作用域內,相同的函式名對應著不同的實現。

函式過載的條件是要求函式引數的型別或個數有所不同。例如:
在這裡插入圖片描述

成員函式過載有三種方式:

在一個類中過載:引數的特徵區分;例如:

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

小結

定義一種新的資料型別,就同時需要定義對這種型別資料的操作,最基本的方法就是定義一系列能夠完成各種運算的函式。

  1. 利用成員函式實現運算,函式中可方便地訪問複數物件中的私有成員。
  2. 利用友元函式實現運算,提供了一種非成員函式訪問複數物件中的私有成員的手段。
  3. 利用函式過載這一種多型性形式,提供在相同的作用域內,相同的函式名對應著不同的實現。

運算子過載

運算子過載是對已有的運算子賦予多重含義。有兩種方式:

  1. 過載為成員函式;
  2. 過載為友元函式

實質

  • 必要性
    C++中預定義的運算子其運算物件只能是基本資料型別,而不適用於使用者自定義型別(如類)
  • 實現機制
    將指定的運算表示式轉化為對運算子函式的呼叫,運算物件轉化為運算子函式的實參。
    編譯系統對過載運算子的選擇,遵循函式過載的選擇原則。

規則和限制

  1. 可以過載C++中除下列運算子外的所有運算子:
    . * :: ?: sizeof
  2. 只能過載C++語言中已有的運算子,不可臆造新的。
  3. 不改變原運算子的優先順序和結合性。
  4. 不能改變運算元個數。
  5. 經過載的運算子,其運算元中至少應該有一個是自定義型別(即類)。

宣告形式

函式型別  operator 運算子(形參)
{
       body;
}
//作為成員函式過載時,第一運算元就是當前物件本身,因此它並不需要出現在引數表中。
  1. 過載為類成員函式時:
    引數個數=原運算元個數-1 (後置++、–除外)引數個數=原運算元個數-1 (後置++、–除外)
  2. 過載為友元函式時:
    引數個=原運算元個數,且至少應該有一個自定義型別的形參。
    由於友元函式不是任何類的成員函式,因此過載時必須在引數表中顯式地給出所有的運算元。

雙目運算子過載為成員函式(題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;
}