西安工業(yè)大學(xué)耿軍雪老師的C課件之多態(tài)性.ppt
《西安工業(yè)大學(xué)耿軍雪老師的C課件之多態(tài)性.ppt》由會員分享,可在線閱讀,更多相關(guān)《西安工業(yè)大學(xué)耿軍雪老師的C課件之多態(tài)性.ppt(95頁珍藏版)》請?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)性 同一名稱,不同的功能實(shí)現(xiàn)方式 運(yùn)算符重載 多態(tài)的經(jīng)典內(nèi)容 虛函數(shù) 動態(tài)綁定 純虛函數(shù) 統(tǒng)一接口 抽象類 定義一個框架,由其衍生對象完善,Object Oriented,,一、多態(tài)性 多態(tài)性:是指不同對象在收到相同的消息時,產(chǎn)生不同的動作——用同一個名字定義不同的函數(shù),執(zhí)行不同但相似的操作——實(shí)現(xiàn)“一個接口,多種方法”。 多態(tài)的實(shí)現(xiàn): 函數(shù)重載:通過形參來區(qū)分 運(yùn)算符重載:只是一種“語法修飾”,是專用格式的函數(shù)重載 虛函數(shù):冠以關(guān)鍵字 virtual 的成員函數(shù)稱為虛函數(shù),Object Oriented,,二、聯(lián)編的概念及分類 1、聯(lián)編的概念 聯(lián)編:源程序經(jīng)過編譯、聯(lián)接成可執(zhí)行文件的過程 ——即將可執(zhí)行代碼聯(lián)編(裝配)在一起的過程。 2、聯(lián)編的分類: 靜態(tài)聯(lián)編(前期聯(lián)編):在運(yùn)行前完成的聯(lián)編——在編譯時完成(要求在編譯時就知道調(diào)用函數(shù)的全部信息)——其優(yōu)點(diǎn)是“效率高”。(重載函數(shù)使用靜態(tài)聯(lián)編。) 動態(tài)聯(lián)編(后期聯(lián)編):在運(yùn)行時才完成的聯(lián)編——在程序運(yùn)行時動態(tài)調(diào)用所需函數(shù)——優(yōu)點(diǎn)是提供了更好的“靈活性”、問題的“抽象性”、程序的“易維護(hù)性”。(switch 語句和 if 語句是動態(tài)聯(lián)編的例子),Object Oriented,,三、多態(tài)性的分類 編譯時多態(tài)性:靜態(tài)聯(lián)編支持的多態(tài)性(靜態(tài)多態(tài)性)——通過函數(shù)重載及運(yùn)算符重載實(shí)現(xiàn)。 運(yùn)行時多態(tài)性:動態(tài)聯(lián)編支持的多態(tài)性(動態(tài)多態(tài)性)——通過虛函數(shù)實(shí)現(xiàn)。 四、函數(shù)重載 同一個類中的同名函數(shù)——參數(shù)個數(shù)不一樣、參數(shù)類型不一樣、參數(shù)個數(shù)及類型不一樣; 不同類中的同名函數(shù)——通過類名調(diào)用或類的對象調(diào)用。 同一個類中同名的普通成員函數(shù)及常量成員函數(shù)——通過const實(shí)現(xiàn)重載。,Object Oriented,第一節(jié) 虛函數(shù)和基類指針,冠以關(guān)鍵字 virtual 的成員函數(shù)稱為虛函數(shù) 實(shí)現(xiàn)運(yùn)行時多態(tài)的關(guān)鍵首先是要說明虛函數(shù),另外,必須用基類指針調(diào)用派生類的不同實(shí)現(xiàn)版本 虛函數(shù)與派生類相結(jié)合,使C++能支持運(yùn)行時多態(tài)性——實(shí)現(xiàn)在基類中定義派生類所擁有的通用“接口”,而在派生類中定義具體的實(shí)現(xiàn)方法,即“一個接口,多種方法”。,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 = },通過基類指針 只能訪問從基類繼承的成員,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指向不同對象,執(zhí)行不同實(shí)現(xiàn)版本,Object Oriented,,注意: 一個虛函數(shù),在派生類層界面相同的重載函數(shù)都保持虛特性 虛函數(shù)必須是類的成員函數(shù),不能是全局函數(shù)和靜態(tài)函數(shù) 不能將友員說明為虛函數(shù),但虛函數(shù)可以是另一個類的友員 析構(gòu)函數(shù)可以是虛函數(shù),但構(gòu)造函數(shù)不能是虛函數(shù) 動態(tài)聯(lián)編只能通過指針或引用來操作虛函數(shù),如果采用其他標(biāo)識對象來操作虛函數(shù),將采用靜態(tài)聯(lián)編方式調(diào)用虛函數(shù)。,Object Oriented,虛析構(gòu)函數(shù),構(gòu)造函數(shù)不能是虛函數(shù)。建立一個派生類對象時,必須從類層次的根開始,沿著繼承路徑逐個調(diào)用基類的構(gòu)造函數(shù) 析構(gòu)函數(shù)可以是虛的。虛析構(gòu)函數(shù)用于指引 delete 運(yùn)算符正確析構(gòu)動態(tài)對象,Object Oriented,5-3普通析構(gòu)函數(shù)在刪除動態(tài)派生類對象的調(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 ;//用基類指針建立派生類的動態(tài)對象 B *Bp2 = new B ;//用派生類指針建立派生類的動態(tài)對象 cout “delete first object:\n“ ; delete Ap;//析構(gòu)由基類指針建立的派生類對象沒有調(diào)用派生類構(gòu)造函數(shù)——問題? cout “delete second object:\n“ ; delete Bp2 ;//析構(gòu)由派生類指針建立的派生類對象正確調(diào)用派生類構(gòu)造函數(shù) },,Object Oriented,5-4虛析構(gòu)函數(shù)在刪除動態(tài)派生類對象的調(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 ; },定義了基類虛析構(gòu)函數(shù),基類指針指向的 派生類動態(tài)對象也可以正確地用delete析構(gòu) 設(shè)計(jì)類層次結(jié)構(gòu)時,提供一個虛析構(gòu)函數(shù), 能夠使派生類對象在不同狀態(tài)下正確調(diào)用析構(gòu)函數(shù),,Object Oriented,第二節(jié) 純虛函數(shù)和抽象類,純虛函數(shù)是一個在基類中說明的虛函數(shù),為各派生類提供一個公共界面,在基類中沒有定義,要求任何派生類都定義自己的版本 純虛函數(shù) 純虛函數(shù)說明形式: virtual 類型 函數(shù)名(參數(shù)表)= 0 ; 一個具有純虛函數(shù)的基類稱為抽象類。,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 ; //派生類對象 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() ; },抽象類至少有一個純虛函數(shù)。 如果抽象類的一個派生類沒有為繼承的純虛函數(shù)定義實(shí)現(xiàn)版本,則它仍然是抽象類。,Object Oriented,5-6,class point { /*……*/ } ; class shape ; // 抽象類 { 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,抽象類不能建立對象 shape *p ; // ok,可以聲明抽象類的指針 shape f ( ) ; // error, 抽象類不能作為返回類型 void g ( shape ) ; // error, 抽象類不能作為參數(shù)類型 shape // ok,可以聲明抽象類的引用,Object Oriented,,class ab_circle : public shape { int radius ; public : void rotate ( int ) { } ; } ;,ab_circle 類仍為抽象類 ab_circle :: draw ( ) 、ab_circle :: rotate ( ) 也是純虛函數(shù),要使 ab_circle 成為非抽象類, 必須作以下說明: class ab_circle : public shape { int radius ; public : void rotate ( int ) ; void draw ( ) ; } ; 并提供 ab_circle :: draw ( ) 和 ab_circle :: rotate ( int ) 的定義,Object Oriented,5-7聲明抽象類指針,#include #include“figure.h“ void main() { figure *p; // 聲明抽象類指針 triangle t; square s; circle c; p= },Object Oriented,5-8抽象類引用,#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)切正方形及外切正方形的面積及周長 #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ù)以一種更簡潔的方式工作,就是賦予已有的運(yùn)算符多重含義。,例如 int x , y ; y = x + y ;,matrix m1 , m2 ; // 矩陣類對象 m2 = Madd ( m1 , m2 ) ; // 調(diào)用函數(shù)計(jì)算兩個矩陣的和,complex c1 , c2 ; // 復(fù)數(shù)類對象 c1 = Cadd (c1 , c2 ) ; // 調(diào)用函數(shù)計(jì)算兩個復(fù)數(shù)的和,能表示為 c1 = c1 + c2 ; ?,能表示為 m1 = m1 + m2 ; ?,定義 運(yùn)算符重載函數(shù),Object Oriented,類以外的運(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)算符重載是對已有的運(yùn)算符賦予多重含義 必要性 C++中預(yù)定義的運(yùn)算符其運(yùn)算對象只能是基本數(shù)據(jù)類型,而不適用于用戶自定義類型(如類) 實(shí)現(xiàn)機(jī)制 將指定的運(yùn)算表達(dá)式轉(zhuǎn)化為對運(yùn)算符函數(shù)的調(diào)用,運(yùn)算對象轉(zhuǎn)化為運(yùn)算符函數(shù)的實(shí)參。 相當(dāng)于a+b =》 +(a,b) 編譯系統(tǒng)對重載運(yùn)算符的選擇,遵循函數(shù)重載的選擇原則。 相當(dāng)于選+(1,2)還是+((1,1),(2,2))?,Object Oriented,,二、重載運(yùn)算符的限制 1、不能重載的算符 . :: * ?: # sizeof 2、重載運(yùn)算符可以對運(yùn)算符作出新的解釋,但原有基本語義不變: 不改變運(yùn)算符的優(yōu)先級和結(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)該有一個是自定義類型。 (否則系統(tǒng)已經(jīng)實(shí)現(xiàn)了) 3、運(yùn)算符通常是對類中的私有成員進(jìn)行操作,故重載運(yùn)算符應(yīng)能訪問類中的私有成員,所以重載運(yùn)算符一般采用成員函數(shù)或友員函數(shù)的形式,Object Oriented,,三、重載為類成員函數(shù) 語法形式為: 類型 類名 :: operator op ( 參數(shù)表 ) { // 相對于該類定義的操作 } 其中,當(dāng)為雙目運(yùn)算符時,參數(shù)表中為一個參數(shù),單目運(yùn)算符時,參數(shù)表為空——通過this指針傳遞。,Object Oriented,,(一)雙目運(yùn)算符的重載 例【5.3.2】重載二個復(fù)數(shù)對象的加、減、乘、除運(yùn)算符——熟悉雙目運(yùn)算符的重載。 1、分析:設(shè)兩個復(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ù)。) 前置和后置,函數(shù)名都是operator ++,所以人為給后置多加一個啞參數(shù),只有類型名。 例【5.3.3】運(yùn)算符前置++和后置++重載為時鐘類的成員函數(shù)。 前置單目運(yùn)算符,重載函數(shù)沒有形參,對于后置單目運(yùn)算符,重載函數(shù)需要有一個整型形參。 操作數(shù)是時鐘類的對象。 實(shí)現(xiàn)時間增加1秒鐘。,Object Oriented,,#include class Clock //時鐘類聲明 { 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ù)類的友元函數(shù)。 兩個操作數(shù)都是復(fù)數(shù)類的對象。 #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ù)由對象Object通過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通過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ù)沒有this指針 不管是成員函數(shù)還是友員函數(shù)重載,運(yùn)算符的使用方法相同。但傳遞參數(shù)的方法不同,實(shí)現(xiàn)代碼不同,應(yīng)用場合也不同。 當(dāng)一元運(yùn)算符的操作數(shù),或者二元運(yùn)算符的左操作數(shù)是該類的一個對象時,定義重載運(yùn)算符函數(shù)為成員函數(shù) 友員函數(shù)重載運(yùn)算符常用于算符的左右操作數(shù)類型不同的情況,左操作數(shù)可以是常數(shù)或其他類型的數(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ù)一樣,通?!?”不用重載,同一類的對象可直接賦值。如:ob1=ob2; 當(dāng)在類中用new分配內(nèi)存空間,在析構(gòu)函數(shù)中用delete中釋放內(nèi)存空間時,應(yīng)重載“=”運(yùn)算符。,例【5.3.6】調(diào)試下列程序,分析出錯的原因,#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,,出錯原因分析:,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 },說明: 類的賦值運(yùn)算符“=”只能重載為成員函數(shù),重載后不能被繼承。,Object Oriented,,注意:對象初始化時的賦值和已創(chuàng)建對象之間的賦值雖然都涉及對象的復(fù)制,但它們是兩個不同的操作。對象初始化首先是為新對象分配存儲空間,然后執(zhí)行對象復(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): 同樣的消息被不同類型的對象接收時導(dǎo)致完全不同的行為,是對類的特定成員函數(shù)的再抽象。 運(yùn)算符重載 對已有的運(yùn)算符賦予多重含義,使用已有運(yùn)算符對用戶自定義類型(比如類)進(jìn)行運(yùn)算操作。 聯(lián)編 程序自身彼此關(guān)聯(lián)的過程稱為聯(lián)編,聯(lián)編確定程序中的操作調(diào)用與執(zhí)行該操作的代碼間的關(guān)系。 靜態(tài)聯(lián)編工作出現(xiàn)在編譯階段。 動態(tài)聯(lián)編工作在程序運(yùn)行時執(zhí)行。虛函數(shù)是動態(tài)聯(lián)編的基礎(chǔ)。,Object Oriented,,純虛函數(shù) 在基類中說明的虛函數(shù),它在該基類中可以不給出函數(shù)體,要求各派生類根據(jù)實(shí)際需要編寫自己的函數(shù)體。 抽象類 帶有純虛函數(shù)的類是抽象類。 抽象類的主要作用是通過它為一個類族建立一個公共的接口,使它們能夠更有效地發(fā)揮多態(tài)特性。,Object Oriented,練習(xí),1、分別使用成員函數(shù)和友員函數(shù)編程序重載運(yùn)算符“+”,使該運(yùn)算符能實(shí)現(xiàn)兩個字符串的連接。,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,抽象類 提供一般屬性,共同操作界面,管理人員類 提供特殊屬性,操作實(shí)現(xiàn),計(jì)時工人類 提供特殊屬性,操作實(shí)現(xiàn),計(jì)件工人類 提供特殊屬性,操作實(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ù),輸出編號、姓名 protected: long number; // 編號 char * name; // 姓名 };,Object Oriented,,3、異質(zhì)鏈表 程序中,用基類類型指針,可以生成一個連接不同派生類對象的動態(tài)鏈表,即每個結(jié)點(diǎn)指針可以指向類層次中不同的派生類對象。 這種結(jié)點(diǎn)類型不相同鏈表稱為異質(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ù),輸出編號、姓名 Employee *next ; protected: long number; // 編號 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:類和對象,定義一個正方形類,該類包括: (1)受保護(hù)類數(shù)據(jù)成員,表示正方形類的邊長,取值范圍在1-30 (2)四個成員函數(shù),分別為: 帶參構(gòu)造函數(shù),初始化正方形邊長; 取邊長函數(shù)GetLen( ); 設(shè)置邊長函數(shù) SetLen( ),重新設(shè)置邊長,并檢查是否在規(guī)定范圍內(nèi); 畫正方形函數(shù) DrawSquare ( ),用邊長做為行數(shù)和每行輸出個數(shù),輸出“*”; (3) 主函數(shù):創(chuàng)建一個邊長為5的正方形;輸出正方形,由鍵盤修改邊長為8;重新輸出正方形。,Object Oriented,for 3:繼承和派生,設(shè)計(jì)兩個類,一個類描述點(diǎn),另一個類描述圓。圓由圓心和半徑構(gòu)成,圓類由點(diǎn)類派生而來,圓心的特性描述由點(diǎn)類繼承下來。要求圓類提供: (1)求圓面積的成員函數(shù) (2) 取圓心坐標(biāo)的兩個函數(shù) Get_X( )和Get_Y( ) (3) 支持初始化的帶參構(gòu)造函數(shù) (4) 主函數(shù),鍵盤輸入圓心坐標(biāo) x,y, 以及半徑 r, 輸出圓面積。,Object Oriented,for 4:繼承和派生,一個圖形是由一個圓和一個矩形構(gòu)成,要求求解圖形的面積。設(shè)計(jì)3個類,其中兩個是基類,一個基類描述圓,另一個基類描述矩形,第三個派生類是由一個圓和一個矩形構(gòu)成的圖形類。圓類包含數(shù)據(jù)成員半徑和求圓面積的成員函數(shù),矩形類包含數(shù)據(jù)成員長和寬、求矩形面積的成員函數(shù)。派生的圖形類提供輸出面積的函數(shù)及實(shí)現(xiàn)初始化的帶參構(gòu)造函數(shù)。 (圓半徑 r=10, 矩形 長=20, 寬=50,輸出面積),,,Object Oriented,for 5:虛函數(shù),編一個程序計(jì)算正方體,球體和圓柱體的表面積和體積。 要求:抽象出一個公共基類container為抽象類,在其中定義求表面積和體積的純虛函數(shù)。抽象類中定義一個公共的數(shù)據(jù)成員radius,此數(shù)值可以作為球體的半徑、正方體的邊長、圓柱體底面圓半徑。由該抽象類派生出的三個類,都有求表面積和體積的實(shí)際定義。鍵盤輸入radius的值后,可以輸出這3種立方體的面積。,Object Oriented,for 6:函數(shù)重載,設(shè)計(jì)一個用來表示直角坐標(biāo)系上點(diǎn)的位置的Location類,然后在主程序中創(chuàng)建兩個對象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 類的應(yīng)用,一圓型游泳池如圖所示,現(xiàn)在需在其周圍建一圓型過道,并在其四周圍上柵欄。柵欄價格為35元/米,過道造價為20元/平方米。過道寬度為3米,游泳池半徑由鍵盤輸入。要求編程計(jì)算并輸出過道和柵欄的造價。,Object Oriented,復(fù)習(xí),結(jié)構(gòu)類型用struct定義,是用戶自定義數(shù)據(jù)類型,由不同類型的數(shù)據(jù)成員組成。結(jié)構(gòu)變量在內(nèi)存占有一片連續(xù)的存儲區(qū)間。結(jié)構(gòu)變量成員用圓點(diǎn)運(yùn)算符和箭頭運(yùn)算符訪問。 類類型是結(jié)構(gòu)類型的拓展,通常用關(guān)鍵字class定義。類是數(shù)據(jù)成員和成員函數(shù)的封裝。類的實(shí)例稱為對象。 數(shù)據(jù)成員是類的屬性,可以為各種合法的C++類型,包括類類型。成員函數(shù)用于操作類的數(shù)據(jù)或在對象之間發(fā)送消息。 類成員由private, protected, public決定訪問特性。public成員集稱為類的接口。不能在類的外部訪問private成員。 構(gòu)造函數(shù)是特殊的成員函數(shù),在創(chuàng)建和初始化對象時自動調(diào)用。析構(gòu)函數(shù)則在對象作用域結(jié)束時自動調(diào)用。,Object Oriented,,靜態(tài)成員是局部于類的成員,它提供一種同類對象的共享機(jī)制。靜態(tài)數(shù)據(jù)成員在編譯時建立并初始化存儲空間。靜態(tài)數(shù)據(jù)成員和靜態(tài)成員函數(shù)依賴于類而使用,與是否建立對象無關(guān)。 友員是類對象操作的一種輔助手段。一個類的友員可以訪問該類各種性質(zhì)的成員。 從編譯器的觀點(diǎn)看,類是一個程序包。定義什么類成員和如何聲明成員的訪問性質(zhì),取決于問題的需要。,Object Oriented,,繼承是面向?qū)ο蟪绦蛟O(shè)計(jì)實(shí)現(xiàn)軟件重用的重要方法。程序員可以在已有類的基礎(chǔ)上定義新的數(shù)據(jù)成員和成員函數(shù)。原有類稱為基類,新的類稱為派生類,這種程序設(shè)計(jì)方法稱為繼承。 派生類成員由基類成員和自身定義的成員組成。單繼承的派生類只有一個基類。多繼承的派生類有多個基類。 對基類成員的訪問性質(zhì)受繼承方式影響。 公有(public)繼承方式,基類的public和protected成員在派生類中性質(zhì)不變; 保護(hù)(protected)繼承,基類的public和protected成員都成為派生類的protected成員; 私有(private)繼承,基類的public和protected成員都成為派生類的private成員。,Object Oriented,,派生類中不可見基類的私有數(shù)據(jù)成員,但這些數(shù)據(jù)存儲單元依然被建立。創(chuàng)建派生類對象時,派生類的構(gòu)造函數(shù)總是先調(diào)用基類構(gòu)造函數(shù)來初始化派生類中的基類成員。調(diào)用基類構(gòu)造函數(shù)可以通過初始化列表實(shí)現(xiàn)數(shù)據(jù)成員的初始化。調(diào)用析構(gòu)函數(shù)的次序和調(diào)用構(gòu)造函數(shù)的次序相反。 類繼承關(guān)系中,覆蓋成員出現(xiàn)訪問的二義性,可以用作用域符顯示指定類成員。 為了避免多繼承類格中的匯點(diǎn)類在派生類對象中產(chǎn)生不同副本,C++提供虛繼承機(jī)制。 多繼承提供了軟件重用的強(qiáng)大功能,也增加了程序的復(fù)雜性。,Object Oriented,,虛函數(shù)和多態(tài)性使軟件設(shè)計(jì)易于擴(kuò)充。 冠以關(guān)鍵字virtual的成員函數(shù)稱為虛函數(shù)。派生類可以重載基類的虛函數(shù),只要接口相同,函數(shù)的虛特性不變。 基類指針可以指向派生類對象;以及基類中擁有虛函數(shù),是支持多態(tài)性的前提。當(dāng)通過基類指針或引用使用虛函數(shù)時,C++在程序運(yùn)行時根據(jù)所指對象類型在類層次中正確選擇重定義的函數(shù)。這種運(yùn)行時的晚期匹配稱為動態(tài)聯(lián)編。 如果通過對象名和點(diǎn)運(yùn)算符方式調(diào)用虛函數(shù),則調(diào)用關(guān)聯(lián)在編譯時由引用對象的類型確定,稱為靜態(tài)聯(lián)編。 如果一個基類中包含虛函數(shù),通常把它的析構(gòu)函數(shù)說明為虛析構(gòu)函數(shù)。這樣,它的所有派生類析構(gòu)函數(shù)也自動成為虛析構(gòu)函數(shù)(即使它們與基類析構(gòu)函數(shù)名字不相同)。虛析構(gòu)函數(shù)使得用delete算符刪除對象時,系統(tǒng)可以正確地調(diào)用析構(gòu)函數(shù)。,Object Oriented,,純虛函數(shù)是在說明時代碼“初始化值”為0的虛函數(shù)。純虛函數(shù)本身沒有實(shí)現(xiàn),由它的派生類定義實(shí)現(xiàn)版本。 具有純虛函數(shù)的類稱為抽象類。抽象類只能作為基類,不能建立實(shí)例化對象。如果抽象類的派生類不提供純虛函數(shù)的實(shí)現(xiàn),則它依然是抽象類。定義了純虛函數(shù)實(shí)現(xiàn)的派生類,即可以建立對象的類稱為具體類。 盡管不能建立抽象類對象,但抽象類機(jī)制提供的軟件抽象和可擴(kuò)展性的手段;抽象類指針使得派生的具體類對象具有多態(tài)操作能力。異質(zhì)鏈表是多態(tài)應(yīng)用的一個實(shí)例。,Object Oriented,,運(yùn)算符重載的作用是令用戶可以像操作基本數(shù)據(jù)類型一樣,用簡潔明確的運(yùn)算符操作- 1.請仔細(xì)閱讀文檔,確保文檔完整性,對于不預(yù)覽、不比對內(nèi)容而直接下載帶來的問題本站不予受理。
- 2.下載的文檔,不會出現(xiàn)我們的網(wǎng)址水印。
- 3、該文檔所得收入(下載+內(nèi)容+預(yù)覽)歸上傳者、原創(chuàng)作者;如果您是本文檔原作者,請點(diǎn)此認(rèn)領(lǐng)!既往收益都?xì)w您。
下載文檔到電腦,查找使用更方便
14.9 積分
下載 |
- 配套講稿:
如PPT文件的首頁顯示word圖標(biāo),表示該P(yáng)PT已包含配套word講稿。雙擊word圖標(biāo)可打開word文檔。
- 特殊限制:
部分文檔作品中含有的國旗、國徽等圖片,僅作為作品整體效果示例展示,禁止商用。設(shè)計(jì)者僅對作品中獨(dú)創(chuàng)性部分享有著作權(quán)。
- 關(guān) 鍵 詞:
- 西安 工業(yè)大學(xué) 耿軍雪 老師 課件 多態(tài)性
鏈接地址:http://appdesigncorp.com/p-2842203.html