日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

第五章-多态性

發布時間:2025/3/21 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 第五章-多态性 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

第五章-多態性

文章目錄

  • 第五章-多態性
    • 多態的類型與實現
    • 運算符重載
      • 1、運算符重載為類的成員函數(非靜態)
      • 單目運算符++的重載
      • 2、運算符重載為類的非成員函數
      • 其他的重載例子
    • 虛函數
    • 虛析構函數
    • 抽象類
    • Tips

多態的類型與實現

多態是指同樣的消息被不同類型的對象接收時導致不同的行為

  • 多態分類
    • 重載多態
    • 強制多態
    • 包含多態
    • 參數多態
  • 多態從實現的角度可以分為兩類
    • 編譯時多態(靜態綁定)
    • 運行時多態(動態綁定)

運行時多態要滿足三個條件:

  • 類之間滿足類型兼容規則
  • 聲明虛函數
  • 由成員函數調用,或者是通過指針、引用來訪問虛函數
  • 運算符重載

    運算符重載是對已有的運算符賦予多重含義,作用于不同類型的數據時有不同的行為(實質上就是函數重載)

    運算符重載的過程是在編譯時完成的

    重載規則:

  • 除了類屬關系運算符.、成員指針運算符.*、域分辨符::、三目運算符?:。其他運算符都可以重載
  • 重載不能改變操作對象個數,同時至少有一個操作對象時自定義類型
  • 重載規則:

    1、運算符重載為類的成員函數(非靜態)

    //函數參數個數比原操作數少一個,后置“++”、“--”除外 返回類型 operator 運算符(形參表) {函數體 } class A{ public:A(){}A(int m,int n):r(m),i(n){}void show(){cout<<r<<"+"<<i<<"i"<<endl;}A operator +(A &m)const{return A(r+m.r,i+m.i);}A operator -(A &m)const{return A(r-m.r,i-m.i);} private:int r,i; }; int main(){A a(2,3),b(4,5),d;d=a+b;d.show();d=b-a;d.show();return 0; }

    單目運算符++的重載

    class A{ public:A(){}A(int m,int n):r(m),i(n){}void show(){cout<<r<<"+"<<i<<"i"<<endl;}A& operator ++(){ //前置++重載 r++;i++;return *this;}A operator ++(int){ //后置++重載 A c=*this;++(*this);return c;} private:int r,i; }; int main(){A a(2,3),d;d=a++;d.show();a.show();return 0; }

    2、運算符重載為類的非成員函數

    //函數參數個數與原操作數一樣 返回類型 operator 運算符(形參表) {函數體 } class A{ public:A(){}A(int m,int n):r(m),i(n){}void show(){cout<<r<<"+"<<i<<"i"<<endl;}friend A operator +(const A&,const A &);friend A operator -(const A&,const A &); private:int r,i; }; A operator +(const A &c1,const A &c2) {return A(c1.r+c2.r,c1.i+c2.i); } A operator -(const A &c1,const A &c2) {return A(c1.r-c2.r,c1.i-c2.i); } int main(){A a(2,3),b(4,5),d;d=a+b;d.show();d=b-a;d.show();return 0; }

    其他的重載例子

    1. 對<<運算符的重載

    class A{ public:A(){}A(int m,int n):r(m),i(n){}friend ostream& operator <<(ostream& out,const A &n); private:int r,i; }; ostream& operator <<(ostream& out,const A &n){out<<"("<<n.r<<","<<n.i<<")";return out; } int main(){A a(2,3);cout<<a;return 0; }

    2. 對 [ ] 運算符的重載

    class A{ public:int x,y,z;int & operator [](int index){switch(index){case 0:return x;case 1:return y;case 2:return z;}} }; int main(){A a;a[1]=10;cout<<a.y<<endl; //此時a[1]即為y return 0; }

    3. 對()運算符的重載

    class A{ public:int x,y,z;int & operator ()(int index){switch(index){case 0:return x;case 1:return y;case 2:return z;}} }; int main(){A a;a(1)=20;cout<<a.y<<endl; //此時a(1)即為y return 0; }

    虛函數

    虛函數必須是非靜態的成員函數

    虛函數是動態綁定的基礎,經過派生之后,在類族中可以實現運行時多態

    一般虛函數成員的語法:

    virtual 函數類型 函數名(參數表);

    class A{ public:virtual void display(); //基類虛函數 }; class B:public A{ public:void display(); //覆蓋基類的虛函數 };
    • 虛函數一般不聲明為內聯函數,因為對虛函數的調用需要動態綁定,而對內聯函數的處理是靜態的
    • 虛函數的聲明只能出現在函數原型聲明中,不能出現在成員函數實現的時候
    • 派生類覆蓋基類的成員函數時,既可以使用virtual關鍵字,也可以不使用。最好是在派生類中寫上virtual,這樣可以清楚地提示這是一個虛函數
    • 如果派生類并顯式沒有給出虛函數聲明,系統會從名稱、參數、返回值三個方面進行檢查,滿足條件后派生類虛函數會自動覆蓋基類虛函數
    class A { public:virtual void display()const; //虛函數 }; class B:public A { public:void display()const; //覆蓋基類虛函數 }; class C:public B { public:void display()const; //覆蓋基類虛函數 }; void A::display()const{cout<<"A::display()"<<endl; } void B::display()const{cout<<"B::display()"<<endl; } void C::display()const{cout<<"C::display()"<<endl; } void fun(A* ptr){ //參數為指向基類對象的指針ptr->display(); } int main() {A a; B b;C c;fun(&a); //用 A對象的指針調用fun函數fun(&b); //用 B對象的指針調用fun函數fun(&c); //用 C對象的指針調用fun函數return 0; } /* 程序運行結果為:A::display()B::display()C::display() */

    如果將fun函數的參數類型設定為A 而不是A* ,那么三次執行的結果都是A::display()。這里運用了類型兼容規則,基類指針可以指向派生類對象,基類引用可以作為派生類對象的別名,但是基類對象不能表示為派生類對象

    注意事項:

  • 只有虛函數是動態綁定的,如果派生類需要修改基類的行為(重寫與基類同名的函數),就應該在基類中將相應的函數聲明為虛函數
  • 必須通過基類的指針或引用調用虛函數時才會發生動態綁定
  • 虛析構函數

    C++中不能聲明虛構造函數,可以聲明虛析構函數

    虛函數作為運行過程中多態的基礎,主要是針對對象的,而構造函數是在對象產生前運行的,因此虛構造函數沒有意義

    一個類析構函數為虛函數,其派生類的析構函數也為虛函數。析構函數設置為虛函數后,在使用指針引用時可以動態綁定,實現運行時多態,保證使用基類指針就能調用適當的析構函數針對不同對象進行清理工作。

    簡單來說,如果有可能通過基類指針調用對象的析構函數(通過delete),就需要讓基類的析構函數成為虛函數,否則會產生不確定的結果

    class A{ public:virtual ~A(){cout<<"A is destructed;"<<endl;} }; class B:public A{ public:~B(){cout<<"B is destructed;"<<endl;} }; int main(){B *pb=new B();A *pa=pb;delete pa;return 0; } /* 程序運行結果為:B is destructed;A is destructed; */

    由于使用了許析構函數,派生類的虛構函數被調用了,動態申請的空間被正確釋放,實現了多態。

    抽象類

    抽象類是帶有純虛函數的類,它處于類的上層,自身無法實例化,只能通過繼承機制,生成非抽象派生類,然后在實例化

    純虛函數是一個在基類中聲明的虛函數,在該基類中沒有定義具體的操作內容,由各派生類根據實際需要給出各自的定義。

    語法形式為:

    virtual 函數類型 函數名(參數表)=0;

    細節 :

  • 在基類中對純虛函數定義的函數體的調用,必須通過“基類 :: 函數名(參數表)”的形式。
  • 如果將析構函數定義為純虛函數,必須給出它的實現,因為派生類析構函數執行之后需要調用基類的析構函數。
    • 抽象類派生出新的類之后,如果派生類給出所有純虛函數的具體實現,派生類就不再是抽象類,可以實例化對象

    • 如果派生類沒有給出全部純虛函數的具體實現,此時派生類仍然是一個抽象類

    • 抽象類不能實例化,但是可以定義一個抽象類的指針和引用。通過指針或引用,可以指向并訪問這個派生類的對象,進而訪問派生類的成員,這種訪問時多態特征的。

    class A { public:virtual void display()const=0; //純虛函數 }; class B:public A { public:void display()const; //覆蓋基類虛函數 }; class C:public B { public:void display()const; //覆蓋基類虛函數 }; void A::display()const{cout<<"A::display()"<<endl; } void B::display()const{cout<<"B::display()"<<endl; } void C::display()const{cout<<"C::display()"<<endl; } void fun(A* ptr){ //參數為指向基類對象的指針ptr->display(); } int main() {//A a;是錯誤的,抽象類不能實例化 B b;C c;fun(&b); //用 B對象的指針調用fun函數fun(&c); //用 C對象的指針調用fun函數return 0; } /* 程序運行結果為:B::display()C::display() */

    Tips

    • 指針類型
      • 可以聲明指向常量的指針,此時不能通過指針改變所指對象的值,但指針本身可以改變去指向另外的對象
      int a=20,b=20; const int* p=&a; p=&b; //正確,p可以指向別的對象 *p=30; //錯誤,不能通過p改變所指對象
      • 可以聲明指針類型的常量,這時指針本身的值不能被改變
      int a,b; int* const p=&a; p=&b; //錯誤,p為指針常量,值不能改變
    • 指向函數的指針
      • 函數指針就是專門用來存放函數代碼首地址的變量,一旦函數指針指向了某個函數,它與函數名便具有相同的作用

      • 聲明一個函數指針時,也需要說明函數的返回值、形參列表,一般語法如下:

        數據類型 (* 函數指針名)(形參表)

      • 函數指針使用前要賦值,讓指針指向一個已經存在的函數代碼起始地址

        函數指針名=函數名;

    void fun(int d){cout<<"hello,"<<d<<endl; } int main() {void (* Pointer)(int); //函數指針Pointer=fun; //函數指針指向funPointer(23); //函數指針調用return 0; }

    總結

    以上是生活随笔為你收集整理的第五章-多态性的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。