西安工業(yè)大學(xué)耿軍雪老師的C課件之多態(tài)性.ppt
《西安工業(yè)大學(xué)耿軍雪老師的C課件之多態(tài)性.ppt》由會(huì)員分享,可在線閱讀,更多相關(guān)《西安工業(yè)大學(xué)耿軍雪老師的C課件之多態(tài)性.ppt(95頁(yè)珍藏版)》請(qǐng)?jiān)谘b配圖網(wǎng)上搜索。
Object Oriented,面向?qū)ο蠹夹g(shù)與C++,計(jì)算機(jī)學(xué)院,Object Oriented,5-0 分析結(jié)果?,#include class point { double x,y; public : point (double i,double j) {x=i;y=j;} double area() {return 0.0;} }; class rectangle : public point { double w,h; public : rectangle(double i,double j,double m,double n):point(i,j) {w=m;h=n;} double area() {return w*h;} }; void fun(point },Object Oriented,第五章 多態(tài)性,本章主要內(nèi)容: 多態(tài)性 同一名稱(chēng),不同的功能實(shí)現(xiàn)方式 運(yùn)算符重載 多態(tài)的經(jīng)典內(nèi)容 虛函數(shù) 動(dòng)態(tài)綁定 純虛函數(shù) 統(tǒng)一接口 抽象類(lèi) 定義一個(gè)框架,由其衍生對(duì)象完善,Object Oriented,,一、多態(tài)性 多態(tài)性:是指不同對(duì)象在收到相同的消息時(shí),產(chǎn)生不同的動(dòng)作——用同一個(gè)名字定義不同的函數(shù),執(zhí)行不同但相似的操作——實(shí)現(xiàn)“一個(gè)接口,多種方法”。 多態(tài)的實(shí)現(xiàn): 函數(shù)重載:通過(guò)形參來(lái)區(qū)分 運(yùn)算符重載:只是一種“語(yǔ)法修飾”,是專(zhuān)用格式的函數(shù)重載 虛函數(shù):冠以關(guān)鍵字 virtual 的成員函數(shù)稱(chēng)為虛函數(shù),Object Oriented,,二、聯(lián)編的概念及分類(lèi) 1、聯(lián)編的概念 聯(lián)編:源程序經(jīng)過(guò)編譯、聯(lián)接成可執(zhí)行文件的過(guò)程 ——即將可執(zhí)行代碼聯(lián)編(裝配)在一起的過(guò)程。 2、聯(lián)編的分類(lèi): 靜態(tài)聯(lián)編(前期聯(lián)編):在運(yùn)行前完成的聯(lián)編——在編譯時(shí)完成(要求在編譯時(shí)就知道調(diào)用函數(shù)的全部信息)——其優(yōu)點(diǎn)是“效率高”。(重載函數(shù)使用靜態(tài)聯(lián)編。) 動(dòng)態(tài)聯(lián)編(后期聯(lián)編):在運(yùn)行時(shí)才完成的聯(lián)編——在程序運(yùn)行時(shí)動(dòng)態(tài)調(diào)用所需函數(shù)——優(yōu)點(diǎn)是提供了更好的“靈活性”、問(wèn)題的“抽象性”、程序的“易維護(hù)性”。(switch 語(yǔ)句和 if 語(yǔ)句是動(dòng)態(tài)聯(lián)編的例子),Object Oriented,,三、多態(tài)性的分類(lèi) 編譯時(shí)多態(tài)性:靜態(tài)聯(lián)編支持的多態(tài)性(靜態(tài)多態(tài)性)——通過(guò)函數(shù)重載及運(yùn)算符重載實(shí)現(xiàn)。 運(yùn)行時(shí)多態(tài)性:動(dòng)態(tài)聯(lián)編支持的多態(tài)性(動(dòng)態(tài)多態(tài)性)——通過(guò)虛函數(shù)實(shí)現(xiàn)。 四、函數(shù)重載 同一個(gè)類(lèi)中的同名函數(shù)——參數(shù)個(gè)數(shù)不一樣、參數(shù)類(lèi)型不一樣、參數(shù)個(gè)數(shù)及類(lèi)型不一樣; 不同類(lèi)中的同名函數(shù)——通過(guò)類(lèi)名調(diào)用或類(lèi)的對(duì)象調(diào)用。 同一個(gè)類(lèi)中同名的普通成員函數(shù)及常量成員函數(shù)——通過(guò)const實(shí)現(xiàn)重載。,Object Oriented,第一節(jié) 虛函數(shù)和基類(lèi)指針,冠以關(guān)鍵字 virtual 的成員函數(shù)稱(chēng)為虛函數(shù) 實(shí)現(xiàn)運(yùn)行時(shí)多態(tài)的關(guān)鍵首先是要說(shuō)明虛函數(shù),另外,必須用基類(lèi)指針調(diào)用派生類(lèi)的不同實(shí)現(xiàn)版本 虛函數(shù)與派生類(lèi)相結(jié)合,使C++能支持運(yùn)行時(shí)多態(tài)性——實(shí)現(xiàn)在基類(lèi)中定義派生類(lèi)所擁有的通用“接口”,而在派生類(lèi)中定義具體的實(shí)現(xiàn)方法,即“一個(gè)接口,多種方法”。,Object Oriented,5-1,#include class Base { public : Base(char xx) { x = xx; } void who() { cout “Base class: “ x “\n“ ; } protected: char x; } ; class First_d : public Base { public : First_d(char xx, char yy):Base(xx) { y = yy; } void who() { cout “First derived class: “ x “, “ y “\n“ ; } protected: char y;} ; class Second_d : public First_d { public : Second_d( char xx, char yy, char zz ) : First_d( xx, yy ) { z = zz; } void who() { cout “Second derived class: “ x “, “ y “, “ z “\n“ ; } protected: char z;} ;,Object Oriented,,void main() { Base B_obj( A ) ; First_d F_obj( T, O ) ; Second_d S_obj( E, N, D ) ; Base * p ; p = },通過(guò)基類(lèi)指針 只能訪問(wèn)從基類(lèi)繼承的成員,Object Oriented,5-2,#include class Base { public : Base(char xx) { x = xx; } virtual void who() { cout “Base class: “ x “\n“ ; } protected: char x; } ; class First_d : public Base { public : First_d(char xx, char yy):Base(xx) { y = yy; } void who() { cout “First derived class: “ x “, “ y “\n“ ; } protected: char y;} ; class Second_d : public First_d { public : Second_d( char xx, char yy, char zz ) : First_d( xx, yy ) { z = zz; } void who() { cout“Second derived class: “x“, “y“, “z“\n“ ; } protected: char z;} ;,Object Oriented,,void main() { Base B_obj( A ) ; First_d F_obj( T, O ) ; Second_d S_obj( E, N, D ) ; Base * p ; p = },由于who()的虛特性 隨著p指向不同對(duì)象,執(zhí)行不同實(shí)現(xiàn)版本,Object Oriented,,注意: 一個(gè)虛函數(shù),在派生類(lèi)層界面相同的重載函數(shù)都保持虛特性 虛函數(shù)必須是類(lèi)的成員函數(shù),不能是全局函數(shù)和靜態(tài)函數(shù) 不能將友員說(shuō)明為虛函數(shù),但虛函數(shù)可以是另一個(gè)類(lèi)的友員 析構(gòu)函數(shù)可以是虛函數(shù),但構(gòu)造函數(shù)不能是虛函數(shù) 動(dòng)態(tài)聯(lián)編只能通過(guò)指針或引用來(lái)操作虛函數(shù),如果采用其他標(biāo)識(shí)對(duì)象來(lái)操作虛函數(shù),將采用靜態(tài)聯(lián)編方式調(diào)用虛函數(shù)。,Object Oriented,虛析構(gòu)函數(shù),構(gòu)造函數(shù)不能是虛函數(shù)。建立一個(gè)派生類(lèi)對(duì)象時(shí),必須從類(lèi)層次的根開(kāi)始,沿著繼承路徑逐個(gè)調(diào)用基類(lèi)的構(gòu)造函數(shù) 析構(gòu)函數(shù)可以是虛的。虛析構(gòu)函數(shù)用于指引 delete 運(yùn)算符正確析構(gòu)動(dòng)態(tài)對(duì)象,Object Oriented,5-3普通析構(gòu)函數(shù)在刪除動(dòng)態(tài)派生類(lèi)對(duì)象的調(diào)用情況,#include class A { public: ~A(){ cout “A::~A() is called.\n“ ; } } ; class B : public A { public: ~B(){ cout “B::~B() is called.\n“ ; } } ; void main() { A *Ap = new B ;//用基類(lèi)指針建立派生類(lèi)的動(dòng)態(tài)對(duì)象 B *Bp2 = new B ;//用派生類(lèi)指針建立派生類(lèi)的動(dòng)態(tài)對(duì)象 cout “delete first object:\n“ ; delete Ap;//析構(gòu)由基類(lèi)指針建立的派生類(lèi)對(duì)象沒(méi)有調(diào)用派生類(lèi)構(gòu)造函數(shù)——問(wèn)題? cout “delete second object:\n“ ; delete Bp2 ;//析構(gòu)由派生類(lèi)指針建立的派生類(lèi)對(duì)象正確調(diào)用派生類(lèi)構(gòu)造函數(shù) },,Object Oriented,5-4虛析構(gòu)函數(shù)在刪除動(dòng)態(tài)派生類(lèi)對(duì)象的調(diào)用情況,#include class A { public: virtual ~A(){ cout “A::~A() is called.\n“ ; } } ; class B : public A { public: ~B(){ cout “B::~B() is called.\n“ ; } } ; void main() { A *Ap = new B ; B *Bp2 = new B ; cout “delete first object:\n“ ; delete Ap; cout “delete second object:\n“ ; delete Bp2 ; },定義了基類(lèi)虛析構(gòu)函數(shù),基類(lèi)指針指向的 派生類(lèi)動(dòng)態(tài)對(duì)象也可以正確地用delete析構(gòu) 設(shè)計(jì)類(lèi)層次結(jié)構(gòu)時(shí),提供一個(gè)虛析構(gòu)函數(shù), 能夠使派生類(lèi)對(duì)象在不同狀態(tài)下正確調(diào)用析構(gòu)函數(shù),,Object Oriented,第二節(jié) 純虛函數(shù)和抽象類(lèi),純虛函數(shù)是一個(gè)在基類(lèi)中說(shuō)明的虛函數(shù),為各派生類(lèi)提供一個(gè)公共界面,在基類(lèi)中沒(méi)有定義,要求任何派生類(lèi)都定義自己的版本 純虛函數(shù) 純虛函數(shù)說(shuō)明形式: virtual 類(lèi)型 函數(shù)名(參數(shù)表)= 0 ; 一個(gè)具有純虛函數(shù)的基類(lèi)稱(chēng)為抽象類(lèi)。,Object Oriented,,class figure //figure.h { protected : double x,y; 5-5 public: void set_dim(double i, double j=0) { x = i ; y = j ; } virtual void show_area() = 0 ; }; class triangle : public figure { public : void show_area() { cout“Triangle with high “x“ and base “y “ has an area of “x*0.5*y“\n“; } }; class square : public figure { public: void show_area() { cout“Square with dimension “x“*“y “ has an area of “x*y“\n“; } }; class circle : public figure { public: void show_area() { cout“Circle with radius “x; cout“ has an area of “3.14*x*x“\n“; } };,Object Oriented,,#include #include“figure.h“ void main() { triangle t ; //派生類(lèi)對(duì)象 square s ; circle c; t.set_dim(10.0,5.0) ; t.show_area(); s.set_dim(10.0,5.0) ; s.show_area() ; c.set_dim(9.0) ; c.show_area() ; },抽象類(lèi)至少有一個(gè)純虛函數(shù)。 如果抽象類(lèi)的一個(gè)派生類(lèi)沒(méi)有為繼承的純虛函數(shù)定義實(shí)現(xiàn)版本,則它仍然是抽象類(lèi)。,Object Oriented,5-6,class point { /*……*/ } ; class shape ; // 抽象類(lèi) { point center ; …… public : point where ( ) { return center ; } void move ( point p ) { enter = p ; draw ( ) ; } virtual void rotate ( int ) = 0 ; // 純虛函數(shù) virtual void draw ( ) = 0 ; // 純虛函數(shù) } ; ….,shape x ; // error,抽象類(lèi)不能建立對(duì)象 shape *p ; // ok,可以聲明抽象類(lèi)的指針 shape f ( ) ; // error, 抽象類(lèi)不能作為返回類(lèi)型 void g ( shape ) ; // error, 抽象類(lèi)不能作為參數(shù)類(lèi)型 shape // ok,可以聲明抽象類(lèi)的引用,Object Oriented,,class ab_circle : public shape { int radius ; public : void rotate ( int ) { } ; } ;,ab_circle 類(lèi)仍為抽象類(lèi) ab_circle :: draw ( ) 、ab_circle :: rotate ( ) 也是純虛函數(shù),要使 ab_circle 成為非抽象類(lèi), 必須作以下說(shuō)明: class ab_circle : public shape { int radius ; public : void rotate ( int ) ; void draw ( ) ; } ; 并提供 ab_circle :: draw ( ) 和 ab_circle :: rotate ( int ) 的定義,Object Oriented,5-7聲明抽象類(lèi)指針,#include #include“figure.h“ void main() { figure *p; // 聲明抽象類(lèi)指針 triangle t; square s; circle c; p= },Object Oriented,5-8抽象類(lèi)引用,#include class Number { public : Number (int i) { val = i ; } virtual void Show() = 0 ; protected: int val ; }; class Hex_type : public Number { public: Hex_type(int i) : Number(i) { } void Show() { cout “Hexadecimal:“ hex val endl ; } }; class Dec_type : public Number { public: Dec_type(int i) : Number(i) { } void Show() { cout “Decimal: “ dec val endl ; } }; class Oct_type : public Number { public: Oct_type(int i) : Number(i) { } void Show() { cout “Octal: “ oct val endl ; } };,Object Oriented,,void fun( Number // Oct_type::Show() },Object Oriented,,應(yīng)用舉例——求圓、圓的內(nèi)切正方形及外切正方形的面積及周長(zhǎng) #include #include class shape { protected : double r; public: shape(double x) {r=x;} virtual double area()=0; virtual double perimeter()=0; };,Object Oriented,,class circle:public shape { public: circle(double x):shape(x) { } double area() {return 3.14*r*r;} double perimeter() {return 2*3.14*r;} }; class in_square:public shape { public: in_square(double x):shape(x) { } double area() {return 2*r*r;} double perimeter() {return 4*sqrt(2)*r;} };,Object Oriented,,class ex_square:public shape { public: ex_square(double x):shape(x) { } double area() {return 4*r*r;} double perimeter() {return 8*r;} }; void main() { shape *p; circle ob1(5.0); in_square ob2(5.0); ex_square ob3(5); p=,Object Oriented,第三節(jié) 運(yùn)算符重載,運(yùn)算符重載使得用戶自定義的數(shù)據(jù)以一種更簡(jiǎn)潔的方式工作,就是賦予已有的運(yùn)算符多重含義。,例如 int x , y ; y = x + y ;,matrix m1 , m2 ; // 矩陣類(lèi)對(duì)象 m2 = Madd ( m1 , m2 ) ; // 調(diào)用函數(shù)計(jì)算兩個(gè)矩陣的和,complex c1 , c2 ; // 復(fù)數(shù)類(lèi)對(duì)象 c1 = Cadd (c1 , c2 ) ; // 調(diào)用函數(shù)計(jì)算兩個(gè)復(fù)數(shù)的和,能表示為 c1 = c1 + c2 ; ?,能表示為 m1 = m1 + m2 ; ?,定義 運(yùn)算符重載函數(shù),Object Oriented,類(lèi)以外的運(yùn)算符重載,#include class complex { public : double real ; double imag; complex(double r=0,double i=0) {real=r;imag=i;} }; complex operator+(complex co1,complex co2)//運(yùn)算符“+”的重載函數(shù) {complex temp; temp.real=co1.real+co2.real; temp.imag=co1.imag+co2.imag; return temp; } void main() { complex com1(1.1,2.2),com2(3.3,4.4),total1,total2; total1=operator+(com1,com2);//運(yùn)算符重載的使用方法1 cout “real1=“total1.real; cout“ imag1=“total1.imagendl; total2=com1+com2;//運(yùn)算符重載的使用方法2 cout “real2=“total2.real; cout“ imag2=“total2.imagendl; },Object Oriented,,一、運(yùn)算符重載的實(shí)質(zhì) 運(yùn)算符重載是對(duì)已有的運(yùn)算符賦予多重含義 必要性 C++中預(yù)定義的運(yùn)算符其運(yùn)算對(duì)象只能是基本數(shù)據(jù)類(lèi)型,而不適用于用戶自定義類(lèi)型(如類(lèi)) 實(shí)現(xiàn)機(jī)制 將指定的運(yùn)算表達(dá)式轉(zhuǎn)化為對(duì)運(yùn)算符函數(shù)的調(diào)用,運(yùn)算對(duì)象轉(zhuǎn)化為運(yùn)算符函數(shù)的實(shí)參。 相當(dāng)于a+b =》 +(a,b) 編譯系統(tǒng)對(duì)重載運(yùn)算符的選擇,遵循函數(shù)重載的選擇原則。 相當(dāng)于選+(1,2)還是+((1,1),(2,2))?,Object Oriented,,二、重載運(yùn)算符的限制 1、不能重載的算符 . :: * ?: # sizeof 2、重載運(yùn)算符可以對(duì)運(yùn)算符作出新的解釋?zhuān)谢菊Z(yǔ)義不變: 不改變運(yùn)算符的優(yōu)先級(jí)和結(jié)合性。(否則難以記憶) 不改變運(yùn)算符所需要的操作數(shù),即單目運(yùn)算符只能重載為單目運(yùn)算符,不能將單目運(yùn)算符重載為雙目運(yùn)算符。 不能創(chuàng)建新的運(yùn)算符,只有系統(tǒng)預(yù)定義的運(yùn)算符才能被重載。 經(jīng)重載的運(yùn)算符,其操作數(shù)中至少應(yīng)該有一個(gè)是自定義類(lèi)型。 (否則系統(tǒng)已經(jīng)實(shí)現(xiàn)了) 3、運(yùn)算符通常是對(duì)類(lèi)中的私有成員進(jìn)行操作,故重載運(yùn)算符應(yīng)能訪問(wèn)類(lèi)中的私有成員,所以重載運(yùn)算符一般采用成員函數(shù)或友員函數(shù)的形式,Object Oriented,,三、重載為類(lèi)成員函數(shù) 語(yǔ)法形式為: 類(lèi)型 類(lèi)名 :: operator op ( 參數(shù)表 ) { // 相對(duì)于該類(lèi)定義的操作 } 其中,當(dāng)為雙目運(yùn)算符時(shí),參數(shù)表中為一個(gè)參數(shù),單目運(yùn)算符時(shí),參數(shù)表為空——通過(guò)this指針傳遞。,Object Oriented,,(一)雙目運(yùn)算符的重載 例【5.3.2】重載二個(gè)復(fù)數(shù)對(duì)象的加、減、乘、除運(yùn)算符——熟悉雙目運(yùn)算符的重載。 1、分析:設(shè)兩個(gè)復(fù)數(shù)a+bi和c+di,則有: 加法:(a+bi)+(c+di)=(a+c)+(b+d)i; 減法:(a+bi)-(c+di)=(a-c)+(b-d)i; 乘法:(a+bi)*(c+di)=(ac-bd)+(ad+bc)i 除法:(a+bi)/(c+di)=(a+bi)*(c-di)/(c2+d2) =(ac+bd)/ (c2+d2)+(bc-ad)i/(c2+d2) 2、程序:,Object Oriented,,#include class complex { private : double real ; double imag; public : complex(double r=0,double i=0) {real=r;imag=i;} complex operator+(complex c); complex operator-(complex c); complex operator*(complex c); complex operator/(complex c); void print(); };,Object Oriented,,complex complex ::operator+(complex c)//重載“+” {complex temp; temp.real=real+c.real; temp.imag=imag+c.imag; return temp; } complex complex ::operator-(complex c)//重載“-” { complex temp; temp.real=real-c.real; temp.imag=imag-c.imag; return temp; },Object Oriented,,complex complex ::operator*(complex c)//重載“*” { complex temp; temp.real=real*c.real-imag*c.imag; temp.imag=real*c.imag+imag*c.real; return temp; } complex complex ::operator/(complex c)//重載“/” {complex temp; double t; t=c.real*c.real+c.imag*c.imag; temp.real=(real*c.real+imag*c.imag)/t; temp.imag=(c.real*imag-real*c.imag)/t; return temp; },Object Oriented,,void complex::print() {cout 0) cout“+“; if (imag!=0) cout imag“i“endl; } void main() { complex A1(2.3,4.6),A2(3.6,2.8),A3,A4,A5,A6; A3=A1+A2;A4=A1-A2; A5=A1*A2;A6=A1/A2; A1.print();A2.print(); A3.print();A4.print(); A5.print();A6.print(); },Object Oriented,,(二)單目運(yùn)算符重載(單目運(yùn)算符重載時(shí)沒(méi)有參數(shù)。) 前置和后置,函數(shù)名都是operator ++,所以人為給后置多加一個(gè)啞參數(shù),只有類(lèi)型名。 例【5.3.3】運(yùn)算符前置++和后置++重載為時(shí)鐘類(lèi)的成員函數(shù)。 前置單目運(yùn)算符,重載函數(shù)沒(méi)有形參,對(duì)于后置單目運(yùn)算符,重載函數(shù)需要有一個(gè)整型形參。 操作數(shù)是時(shí)鐘類(lèi)的對(duì)象。 實(shí)現(xiàn)時(shí)間增加1秒鐘。,Object Oriented,,#include class Clock //時(shí)鐘類(lèi)聲明 { public: //外部接口 Clock(int NewH=0, int NewM=0, int NewS=0) {Hour=NewH;Minute=NewM;Second=NewS;} void ShowTime() {coutHour“:“Minute“:“Secondendl;} void operator ++(); //前置單目運(yùn)算符重載 void operator ++(int); //后置單目運(yùn)算符重載 private: //私有數(shù)據(jù)成員 int Hour, Minute, Second; };,Object Oriented,,void Clock::operator ++( ) //前置單目運(yùn)算符重載函數(shù) { Second++; if(Second=60) //考慮進(jìn)位 { Second=Second-60; Minute++; if(Minute=60) { Minute=Minute-60; Hour++; Hour=Hour%24; } } cout“++Clock: “; },Object Oriented,,void Clock::operator ++(int) //后置單目運(yùn)算符重載 { Second++; if(Second=60) { Second=Second-60; Minute++; if(Minute=60) { Minute=Minute-60; Hour++; Hour=Hour%24; } } cout“Clock++: “; },Object Oriented,,void main() { Clock myClock(23,59,59); cout“First time output:“; myClock.ShowTime(); myClock++; myClock.ShowTime(); ++myClock; myClock.ShowTime(); },Object Oriented,,四、重載為友元函數(shù) 例【5.3.4】將+、-(雙目)重載為復(fù)數(shù)類(lèi)的友元函數(shù)。 兩個(gè)操作數(shù)都是復(fù)數(shù)類(lèi)的對(duì)象。 #include class complex { private : double real ; double imag; public : complex(double r=0,double i=0) {real=r;imag=i;} void print(); friend complex operator+(complex a,complex b); friend complex operator-(complex a,complex b); friend complex operator*(complex a,complex b); friend complex operator/(complex a,complex b); };,Object Oriented,,complex operator+(complex a,complex b) {complex temp; temp.real=a.real+b.real; temp.imag=a.imag+b.imag; return temp; } complex operator-(complex a,complex b) {complex temp; temp.real=a.real-b.real; temp.imag=a.imag-b.imag; return temp; },Object Oriented,,complex operator*(complex a,complex b) {complex temp; temp.real=a.real*b.real-a.imag*b.imag; temp.imag=a.real*b.imag+a.imag*b.real; return temp; } complex operator/(complex a,complex b) {complex temp; double t; t=b.real*b.real+b.imag*b.imag; temp.real=(a.real*b.real+a.imag*b.imag)/t; temp.imag=(b.real*a.imag-a.real*b.imag)/t; return temp; },Object Oriented,,void complex::print() {cout 0) cout“+“; if (imag!=0) cout imag“i“endl; } void main() { complex A1(2.3,4.6),A2(3.6,2.8),A3,A4,A5,A6; A3=A1+A2; A4=A1-A2; A5=A1*A2; A6=A1/A2; A1.print(); A2.print(); A3.print(); A4.print(); A5.print(); A6.print(); },Object Oriented,,重載為成員函數(shù),解釋為: Object . operator op () 操作數(shù)由對(duì)象Object通過(guò)this指針隱含傳遞 重載為友員函數(shù),解釋為: operator op (Object) 操作數(shù)由參數(shù)表的參數(shù)Object提供,1.一元運(yùn)算符,Object op 或 op Object,Object Oriented,,重載為成員函數(shù),解釋為: ObjectL . operator op ( ObjectR ) 左操作數(shù)由ObjectL通過(guò)this指針傳遞,右操作數(shù)由參數(shù)ObjectR傳遞 重載為友員函數(shù),解釋為: operator op ( ObjectL, ObjectR ) 左右操作數(shù)都由參數(shù)傳遞,2.二元運(yùn)算符,ObjectL op ObjectR,Object Oriented,,總結(jié) 運(yùn)算符函數(shù)可以重載為成員函數(shù)或友員函數(shù) 關(guān)鍵區(qū)別在于成員函數(shù)具有 this 指針,友員函數(shù)沒(méi)有this指針 不管是成員函數(shù)還是友員函數(shù)重載,運(yùn)算符的使用方法相同。但傳遞參數(shù)的方法不同,實(shí)現(xiàn)代碼不同,應(yīng)用場(chǎng)合也不同。 當(dāng)一元運(yùn)算符的操作數(shù),或者二元運(yùn)算符的左操作數(shù)是該類(lèi)的一個(gè)對(duì)象時(shí),定義重載運(yùn)算符函數(shù)為成員函數(shù) 友員函數(shù)重載運(yùn)算符常用于算符的左右操作數(shù)類(lèi)型不同的情況,左操作數(shù)可以是常數(shù)或其他類(lèi)型的數(shù)。 運(yùn)算符=、( )、[ ]、-不能用友元函數(shù)重載,(只能用成員函數(shù)重載),Object Oriented,,,class nclass { private : int a ; int b ; public : nclass operator+(int x); … }; nclass nclass :: operator+(int x) { nclass temp ; temp.a=a+x; temp.b=b+x; return temp; },void main() { nclass ob1,ob2; … ob2=ob1+100; … ob2=100+ob1; … },程序中: ob2=ob1+100;——正確 ob2=100+ob1;——不正確,為什么?,,例【5.3.5】常數(shù)與復(fù)數(shù)相加。 #include class complex {private : double real ; double imag; public : complex(double r=0,double i=0) {real=r;imag=i;} void show() {cout “real=“real“ imag=“imagendl;} friend complex operator+(complex co,double x); friend complex operator+(double x,complex co); };,Object Oriented,,complex operator+(complex co,double x) {complex temp; temp.real=co.real+x; temp.imag=co.imag; return temp; } complex operator+(double x,complex co) {complex temp; temp.real=x+co.real; temp.imag=co.imag; return temp; } void main() { complex com1(1.1,2.2),com2,com3; com2=com1+10.0; com2.show(); com3=20.0+com1; com3.show(); },Object Oriented,,五、賦值運(yùn)算符“=”的重載 同拷貝構(gòu)造函數(shù)一樣,通常“=”不用重載,同一類(lèi)的對(duì)象可直接賦值。如:ob1=ob2; 當(dāng)在類(lèi)中用new分配內(nèi)存空間,在析構(gòu)函數(shù)中用delete中釋放內(nèi)存空間時(shí),應(yīng)重載“=”運(yùn)算符。,例【5.3.6】調(diào)試下列程序,分析出錯(cuò)的原因,#include #include class string { char *ptr; public : string(char *s) {ptr=new char[strlen(s)+1]; strcpy(ptr,s); } ~string() {delete ptr;} void print() {cout ptrendl;} };,void main() {string p1(“chen“); {string p2(“ “); p2=p1; cout “p2: “; p2.print(); } cout“p1: “; p1.print(); },Object Oriented,,void main() {string p1(“chen“); {string p2(“ “); p2=p1; cout “p2: “; p2.print(); } cout“p1: “; p1.print(); },Object Oriented,,出錯(cuò)原因分析:,Object Oriented,,解決辦法:重載“=”運(yùn)算符 例【5.3.7】將上例程序改為:,#include #include class string { char *ptr; public : string(char *s) {ptr=new char[strlen(s)+1]; strcpy(ptr,s); } ~string() {delete []ptr;} void print() {cout ptrendl;} string ,Object Oriented,,string },說(shuō)明: 類(lèi)的賦值運(yùn)算符“=”只能重載為成員函數(shù),重載后不能被繼承。,Object Oriented,,注意:對(duì)象初始化時(shí)的賦值和已創(chuàng)建對(duì)象之間的賦值雖然都涉及對(duì)象的復(fù)制,但它們是兩個(gè)不同的操作。對(duì)象初始化首先是為新對(duì)象分配存儲(chǔ)空間,然后執(zhí)行對(duì)象復(fù)制。 如:Point p1, p2(3.14, 4.06); Point p3=p2; //調(diào)用拷貝構(gòu)造初始化函數(shù) p1=p2; //調(diào)用賦值運(yùn)算符重載,Object Oriented,本章小結(jié),多態(tài): 同樣的消息被不同類(lèi)型的對(duì)象接收時(shí)導(dǎo)致完全不同的行為,是對(duì)類(lèi)的特定成員函數(shù)的再抽象。 運(yùn)算符重載 對(duì)已有的運(yùn)算符賦予多重含義,使用已有運(yùn)算符對(duì)用戶自定義類(lèi)型(比如類(lèi))進(jìn)行運(yùn)算操作。 聯(lián)編 程序自身彼此關(guān)聯(lián)的過(guò)程稱(chēng)為聯(lián)編,聯(lián)編確定程序中的操作調(diào)用與執(zhí)行該操作的代碼間的關(guān)系。 靜態(tài)聯(lián)編工作出現(xiàn)在編譯階段。 動(dòng)態(tài)聯(lián)編工作在程序運(yùn)行時(shí)執(zhí)行。虛函數(shù)是動(dòng)態(tài)聯(lián)編的基礎(chǔ)。,Object Oriented,,純虛函數(shù) 在基類(lèi)中說(shuō)明的虛函數(shù),它在該基類(lèi)中可以不給出函數(shù)體,要求各派生類(lèi)根據(jù)實(shí)際需要編寫(xiě)自己的函數(shù)體。 抽象類(lèi) 帶有純虛函數(shù)的類(lèi)是抽象類(lèi)。 抽象類(lèi)的主要作用是通過(guò)它為一個(gè)類(lèi)族建立一個(gè)公共的接口,使它們能夠更有效地發(fā)揮多態(tài)特性。,Object Oriented,練習(xí),1、分別使用成員函數(shù)和友員函數(shù)編程序重載運(yùn)算符“+”,使該運(yùn)算符能實(shí)現(xiàn)兩個(gè)字符串的連接。,Object Oriented,,#include“iostream.h“ #include class string { public: string(){ *str = \0; } string( char *pstr ) { strcpy( str,pstr ); } char *gets() { return str; } string operator+( string obj ); private: char str[100]; }; string string::operator+( string obj ) { strcat( str,obj.str ); return str; //或return *this } void main() { string obj1( “Visual“ ),obj2( “ C++“ ),obj3; obj3 = obj1 + obj2; cout obj3.gets() endl; },Object Oriented,,#include #include class string { public: string(){ *str= \0; } string( char *pstr ) { strcpy( str,pstr ); } char *gets() { return str; } friend string operator+( string obj1,string obj2 ); private: char str[100]; }; string operator+( string obj1,string obj2 ) { string tempobj; strcat( tempobj.str,obj1.str ); strcat( tempobj.str,obj2.str ); return tempobj; } void main() { string obj1( “Visual“ ),obj2( “ C++“ ),obj3; obj3 = obj1 + obj2; cout obj3.gets() endl; },Object Oriented,,Employee,抽象類(lèi) 提供一般屬性,共同操作界面,管理人員類(lèi) 提供特殊屬性,操作實(shí)現(xiàn),計(jì)時(shí)工人類(lèi) 提供特殊屬性,操作實(shí)現(xiàn),計(jì)件工人類(lèi) 提供特殊屬性,操作實(shí)現(xiàn),2.計(jì)算雇員工資,Object Oriented,,class Employee { public: Employee(long no, char* na); virtual ~Employee(); //虛析構(gòu)函數(shù) char * getName(); long getNumber(); virtual double earnings() =0; //純虛函數(shù),計(jì)算月薪 virtual void print(); //虛函數(shù),輸出編號(hào)、姓名 protected: long number; // 編號(hào) char * name; // 姓名 };,Object Oriented,,3、異質(zhì)鏈表 程序中,用基類(lèi)類(lèi)型指針,可以生成一個(gè)連接不同派生類(lèi)對(duì)象的動(dòng)態(tài)鏈表,即每個(gè)結(jié)點(diǎn)指針可以指向類(lèi)層次中不同的派生類(lèi)對(duì)象。 這種結(jié)點(diǎn)類(lèi)型不相同鏈表稱(chēng)為異質(zhì)鏈表。,Object Oriented,,class Employee { public: Employee(long no, char* na); virtual ~Employee(); //虛析構(gòu)函數(shù) char * getName(); long getNumber(); virtual double earnings() =0; //純虛函數(shù),計(jì)算月薪 virtual void print(); //虛函數(shù),輸出編號(hào)、姓名 Employee *next ; protected: long number; // 編號(hào) char * name; // 姓名 };,Object Oriented,,void AddFront( Employee * } },Object Oriented,for 1:,#include #include class Point { public: Point(double xi, double yi) { X = xi ; Y = yi ;} double GetX() { return X ; } double GetY() { return Y ; } friend double Distance ( Point },Object Oriented,for 2:類(lèi)和對(duì)象,定義一個(gè)正方形類(lèi),該類(lèi)包括: (1)受保護(hù)類(lèi)數(shù)據(jù)成員,表示正方形類(lèi)的邊長(zhǎng),取值范圍在1-30 (2)四個(gè)成員函數(shù),分別為: 帶參構(gòu)造函數(shù),初始化正方形邊長(zhǎng); 取邊長(zhǎng)函數(shù)GetLen( ); 設(shè)置邊長(zhǎng)函數(shù) SetLen( ),重新設(shè)置邊長(zhǎng),并檢查是否在規(guī)定范圍內(nèi); 畫(huà)正方形函數(shù) DrawSquare ( ),用邊長(zhǎng)做為行數(shù)和每行輸出個(gè)數(shù),輸出“*”; (3) 主函數(shù):創(chuàng)建一個(gè)邊長(zhǎng)為5的正方形;輸出正方形,由鍵盤(pán)修改邊長(zhǎng)為8;重新輸出正方形。,Object Oriented,for 3:繼承和派生,設(shè)計(jì)兩個(gè)類(lèi),一個(gè)類(lèi)描述點(diǎn),另一個(gè)類(lèi)描述圓。圓由圓心和半徑構(gòu)成,圓類(lèi)由點(diǎn)類(lèi)派生而來(lái),圓心的特性描述由點(diǎn)類(lèi)繼承下來(lái)。要求圓類(lèi)提供: (1)求圓面積的成員函數(shù) (2) 取圓心坐標(biāo)的兩個(gè)函數(shù) Get_X( )和Get_Y( ) (3) 支持初始化的帶參構(gòu)造函數(shù) (4) 主函數(shù),鍵盤(pán)輸入圓心坐標(biāo) x,y, 以及半徑 r, 輸出圓面積。,Object Oriented,for 4:繼承和派生,一個(gè)圖形是由一個(gè)圓和一個(gè)矩形構(gòu)成,要求求解圖形的面積。設(shè)計(jì)3個(gè)類(lèi),其中兩個(gè)是基類(lèi),一個(gè)基類(lèi)描述圓,另一個(gè)基類(lèi)描述矩形,第三個(gè)派生類(lèi)是由一個(gè)圓和一個(gè)矩形構(gòu)成的圖形類(lèi)。圓類(lèi)包含數(shù)據(jù)成員半徑和求圓面積的成員函數(shù),矩形類(lèi)包含數(shù)據(jù)成員長(zhǎng)和寬、求矩形面積的成員函數(shù)。派生的圖形類(lèi)提供輸出面積的函數(shù)及實(shí)現(xiàn)初始化的帶參構(gòu)造函數(shù)。 (圓半徑 r=10, 矩形 長(zhǎng)=20, 寬=50,輸出面積),,,Object Oriented,for 5:虛函數(shù),編一個(gè)程序計(jì)算正方體,球體和圓柱體的表面積和體積。 要求:抽象出一個(gè)公共基類(lèi)container為抽象類(lèi),在其中定義求表面積和體積的純虛函數(shù)。抽象類(lèi)中定義一個(gè)公共的數(shù)據(jù)成員radius,此數(shù)值可以作為球體的半徑、正方體的邊長(zhǎng)、圓柱體底面圓半徑。由該抽象類(lèi)派生出的三個(gè)類(lèi),都有求表面積和體積的實(shí)際定義。鍵盤(pán)輸入radius的值后,可以輸出這3種立方體的面積。,Object Oriented,for 6:函數(shù)重載,設(shè)計(jì)一個(gè)用來(lái)表示直角坐標(biāo)系上點(diǎn)的位置的Location類(lèi),然后在主程序中創(chuàng)建兩個(gè)對(duì)象A和 B,要求A在第三象限,B在第二象限,計(jì)算給定兩點(diǎn)之間的距離并按如下格式輸出結(jié)果: A(x1,y1),B(x2,y2) Distance=d 其中x1,y1,x2,y2為指定值,d為計(jì)算結(jié)果。,Object Oriented,for7 類(lèi)的應(yīng)用,一圓型游泳池如圖所示,現(xiàn)在需在其周?chē)ㄒ粓A型過(guò)道,并在其四周?chē)蠔艡?。柵欄價(jià)格為35元/米,過(guò)道造價(jià)為20元/平方米。過(guò)道寬度為3米,游泳池半徑由鍵盤(pán)輸入。要求編程計(jì)算并輸出過(guò)道和柵欄的造價(jià)。,Object Oriented,復(fù)習(xí),結(jié)構(gòu)類(lèi)型用struct定義,是用戶自定義數(shù)據(jù)類(lèi)型,由不同類(lèi)型的數(shù)據(jù)成員組成。結(jié)構(gòu)變量在內(nèi)存占有一片連續(xù)的存儲(chǔ)區(qū)間。結(jié)構(gòu)變量成員用圓點(diǎn)運(yùn)算符和箭頭運(yùn)算符訪問(wèn)。 類(lèi)類(lèi)型是結(jié)構(gòu)類(lèi)型的拓展,通常用關(guān)鍵字class定義。類(lèi)是數(shù)據(jù)成員和成員函數(shù)的封裝。類(lèi)的實(shí)例稱(chēng)為對(duì)象。 數(shù)據(jù)成員是類(lèi)的屬性,可以為各種合法的C++類(lèi)型,包括類(lèi)類(lèi)型。成員函數(shù)用于操作類(lèi)的數(shù)據(jù)或在對(duì)象之間發(fā)送消息。 類(lèi)成員由private, protected, public決定訪問(wèn)特性。public成員集稱(chēng)為類(lèi)的接口。不能在類(lèi)的外部訪問(wèn)private成員。 構(gòu)造函數(shù)是特殊的成員函數(shù),在創(chuàng)建和初始化對(duì)象時(shí)自動(dòng)調(diào)用。析構(gòu)函數(shù)則在對(duì)象作用域結(jié)束時(shí)自動(dòng)調(diào)用。,Object Oriented,,靜態(tài)成員是局部于類(lèi)的成員,它提供一種同類(lèi)對(duì)象的共享機(jī)制。靜態(tài)數(shù)據(jù)成員在編譯時(shí)建立并初始化存儲(chǔ)空間。靜態(tài)數(shù)據(jù)成員和靜態(tài)成員函數(shù)依賴于類(lèi)而使用,與是否建立對(duì)象無(wú)關(guān)。 友員是類(lèi)對(duì)象操作的一種輔助手段。一個(gè)類(lèi)的友員可以訪問(wèn)該類(lèi)各種性質(zhì)的成員。 從編譯器的觀點(diǎn)看,類(lèi)是一個(gè)程序包。定義什么類(lèi)成員和如何聲明成員的訪問(wèn)性質(zhì),取決于問(wèn)題的需要。,Object Oriented,,繼承是面向?qū)ο蟪绦蛟O(shè)計(jì)實(shí)現(xiàn)軟件重用的重要方法。程序員可以在已有類(lèi)的基礎(chǔ)上定義新的數(shù)據(jù)成員和成員函數(shù)。原有類(lèi)稱(chēng)為基類(lèi),新的類(lèi)稱(chēng)為派生類(lèi),這種程序設(shè)計(jì)方法稱(chēng)為繼承。 派生類(lèi)成員由基類(lèi)成員和自身定義的成員組成。單繼承的派生類(lèi)只有一個(gè)基類(lèi)。多繼承的派生類(lèi)有多個(gè)基類(lèi)。 對(duì)基類(lèi)成員的訪問(wèn)性質(zhì)受繼承方式影響。 公有(public)繼承方式,基類(lèi)的public和protected成員在派生類(lèi)中性質(zhì)不變; 保護(hù)(protected)繼承,基類(lèi)的public和protected成員都成為派生類(lèi)的protected成員; 私有(private)繼承,基類(lèi)的public和protected成員都成為派生類(lèi)的private成員。,Object Oriented,,派生類(lèi)中不可見(jiàn)基類(lèi)的私有數(shù)據(jù)成員,但這些數(shù)據(jù)存儲(chǔ)單元依然被建立。創(chuàng)建派生類(lèi)對(duì)象時(shí),派生類(lèi)的構(gòu)造函數(shù)總是先調(diào)用基類(lèi)構(gòu)造函數(shù)來(lái)初始化派生類(lèi)中的基類(lèi)成員。調(diào)用基類(lèi)構(gòu)造函數(shù)可以通過(guò)初始化列表實(shí)現(xiàn)數(shù)據(jù)成員的初始化。調(diào)用析構(gòu)函數(shù)的次序和調(diào)用構(gòu)造函數(shù)的次序相反。 類(lèi)繼承關(guān)系中,覆蓋成員出現(xiàn)訪問(wèn)的二義性,可以用作用域符顯示指定類(lèi)成員。 為了避免多繼承類(lèi)格中的匯點(diǎn)類(lèi)在派生類(lèi)對(duì)象中產(chǎn)生不同副本,C++提供虛繼承機(jī)制。 多繼承提供了軟件重用的強(qiáng)大功能,也增加了程序的復(fù)雜性。,Object Oriented,,虛函數(shù)和多態(tài)性使軟件設(shè)計(jì)易于擴(kuò)充。 冠以關(guān)鍵字virtual的成員函數(shù)稱(chēng)為虛函數(shù)。派生類(lèi)可以重載基類(lèi)的虛函數(shù),只要接口相同,函數(shù)的虛特性不變。 基類(lèi)指針可以指向派生類(lèi)對(duì)象;以及基類(lèi)中擁有虛函數(shù),是支持多態(tài)性的前提。當(dāng)通過(guò)基類(lèi)指針或引用使用虛函數(shù)時(shí),C++在程序運(yùn)行時(shí)根據(jù)所指對(duì)象類(lèi)型在類(lèi)層次中正確選擇重定義的函數(shù)。這種運(yùn)行時(shí)的晚期匹配稱(chēng)為動(dòng)態(tài)聯(lián)編。 如果通過(guò)對(duì)象名和點(diǎn)運(yùn)算符方式調(diào)用虛函數(shù),則調(diào)用關(guān)聯(lián)在編譯時(shí)由引用對(duì)象的類(lèi)型確定,稱(chēng)為靜態(tài)聯(lián)編。 如果一個(gè)基類(lèi)中包含虛函數(shù),通常把它的析構(gòu)函數(shù)說(shuō)明為虛析構(gòu)函數(shù)。這樣,它的所有派生類(lèi)析構(gòu)函數(shù)也自動(dòng)成為虛析構(gòu)函數(shù)(即使它們與基類(lèi)析構(gòu)函數(shù)名字不相同)。虛析構(gòu)函數(shù)使得用delete算符刪除對(duì)象時(shí),系統(tǒng)可以正確地調(diào)用析構(gòu)函數(shù)。,Object Oriented,,純虛函數(shù)是在說(shuō)明時(shí)代碼“初始化值”為0的虛函數(shù)。純虛函數(shù)本身沒(méi)有實(shí)現(xiàn),由它的派生類(lèi)定義實(shí)現(xiàn)版本。 具有純虛函數(shù)的類(lèi)稱(chēng)為抽象類(lèi)。抽象類(lèi)只能作為基類(lèi),不能建立實(shí)例化對(duì)象。如果抽象類(lèi)的派生類(lèi)不提供純虛函數(shù)的實(shí)現(xiàn),則它依然是抽象類(lèi)。定義了純虛函數(shù)實(shí)現(xiàn)的派生類(lèi),即可以建立對(duì)象的類(lèi)稱(chēng)為具體類(lèi)。 盡管不能建立抽象類(lèi)對(duì)象,但抽象類(lèi)機(jī)制提供的軟件抽象和可擴(kuò)展性的手段;抽象類(lèi)指針使得派生的具體類(lèi)對(duì)象具有多態(tài)操作能力。異質(zhì)鏈表是多態(tài)應(yīng)用的一個(gè)實(shí)例。,Object Oriented,,運(yùn)算符重載的作用是令用戶可以像操作基本數(shù)據(jù)類(lèi)型一樣,用簡(jiǎn)潔明確的運(yùn)算符操作- 1.請(qǐng)仔細(xì)閱讀文檔,確保文檔完整性,對(duì)于不預(yù)覽、不比對(duì)內(nèi)容而直接下載帶來(lái)的問(wèn)題本站不予受理。
- 2.下載的文檔,不會(huì)出現(xiàn)我們的網(wǎng)址水印。
- 3、該文檔所得收入(下載+內(nèi)容+預(yù)覽)歸上傳者、原創(chuàng)作者;如果您是本文檔原作者,請(qǐng)點(diǎn)此認(rèn)領(lǐng)!既往收益都?xì)w您。
下載文檔到電腦,查找使用更方便
14.9 積分
下載 |
- 配套講稿:
如PPT文件的首頁(yè)顯示word圖標(biāo),表示該P(yáng)PT已包含配套word講稿。雙擊word圖標(biāo)可打開(kāi)word文檔。
- 特殊限制:
部分文檔作品中含有的國(guó)旗、國(guó)徽等圖片,僅作為作品整體效果示例展示,禁止商用。設(shè)計(jì)者僅對(duì)作品中獨(dú)創(chuàng)性部分享有著作權(quán)。
- 關(guān) 鍵 詞:
- 西安 工業(yè)大學(xué) 耿軍雪 老師 課件 多態(tài)性
鏈接地址:http://www.820124.com/p-2842203.html