(一)重載運算符:
(1)聲明與定義格式 一般是類內聲明,類外定義,雖然可以在類內定義,但 寫前面堆一堆不好看!!! 類內聲明 :
class Demo
{返回值類型 operator 運算符(形參表);
}
類外定義:
返回類型 Demo(類名)::operator運算符(形參表)
{函數體
}
(2)雙目運算符重載為成員函數 當重載運算符為雙目運算符時,形參表中只有一個參數作為右操作數。當前對象作為左操作數,通過this指針隱式傳遞給函數,一個例子來介紹。 實例: 寫到最后突然想起來,用int不能實現浮點數的全部特性0.03就不能實現,所以僅作為一個例子。
class Myfloat
{int inter;int deci;
public:Myfloat(int a,int b):inter(a),deci(b){}Myfloat operator+(Myfloat const &temp) const;Myfloat operator-(Myfloat const &temp) const;
};
Myfloat Myfloat::operator+(Myfloat const &temp) const
{return Myfloat(inter+temp.inter,deci+temp.deci);
}
Myfloat Myfloat::operator-(Myfloat const &temp) const
{return Myfloat(inter-temp.inter,deci-temp.deci);
}
現在只是重載了加減號,實現了自定義浮點數的運算,但是還不成熟,咱們一點一點來豐滿這個代碼,這個類。(3)單目運算符重載為成員函數 此時參數表中沒有參數,只有當前對象作為運算符的一個操作數。 實例:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std
;
class Myfloat
{ int inter
; int deci
;
public
: Myfloat ( int a
, int b
) : inter ( a
) , deci ( b
) { } Myfloat operator
+ ( Myfloat
const & temp
) const ; Myfloat operator
- ( Myfloat
const & temp
) const ; Myfloat operator
-- ( ) ; Myfloat operator
++ ( ) ; Myfloat operator
-- ( int ) ; Myfloat operator
++ ( int ) ;
} ;
Myfloat Myfloat
: : operator
+ ( Myfloat
const & temp
) const
{ return Myfloat ( inter
+ temp
. inter
, deci
+ temp
. deci
) ;
}
Myfloat Myfloat
: : operator
- ( Myfloat
const & temp
) const
{ return Myfloat ( inter
- temp
. inter
, deci
- temp
. deci
) ;
}
Myfloat Myfloat
: : operator
-- ( ) { return Myfloat ( inter
-- , deci
) ; }
Myfloat Myfloat
: : operator
++ ( ) { return Myfloat ( inter
++ , deci
) ; }
Myfloat Myfloat
: : operator
-- ( int ) { return Myfloat ( -- inter
, deci
) ; }
要區分前置與后置運算要加一個(需操作數)告訴機器是前置還是后置。
(3) 友元函數重載+重載輸入輸出流(用的稀爛用的多比較重要) 在左右操作數類型不同時上述重載方式都不能正常使用,這時候就需要兩個操作數,在類外重載,因類外不能直接調用,所以要把該函數聲明為類的友元。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std
;
class Myfloat
{ int inter
; int deci
;
public
: Myfloat ( int a
, int b
) : inter ( a
) , deci ( b
) { } Myfloat operator
+ ( Myfloat
const & temp
) const ; Myfloat operator
- ( Myfloat
const & temp
) const ; Myfloat operator
-- ( ) ; Myfloat operator
++ ( ) ; Myfloat operator
-- ( int ) ; Myfloat operator
++ ( int ) ; friend ostream
& operator
<< ( ostream out
, Myfloat
& w
) ; friend istream
& operator
>> ( istream in
, Myfloat
& w
) ;
} ;
Myfloat Myfloat
: : operator
+ ( Myfloat
const & temp
) const { return Myfloat ( inter
+ temp
. inter
, deci
+ temp
. deci
) ; }
Myfloat Myfloat
: : operator
- ( Myfloat
const & temp
) const { return Myfloat ( inter
- temp
. inter
, deci
- temp
. deci
) ; }
Myfloat Myfloat
: : operator
-- ( ) { return Myfloat ( inter
-- , deci
) ; }
Myfloat Myfloat
: : operator
++ ( ) { return Myfloat ( inter
++ , deci
) ; }
Myfloat Myfloat
: : operator
-- ( int ) { return Myfloat ( -- inter
, deci
) ; }
Myfloat Myfloat
: : operator
++ ( int ) { return Myfloat ( ++ inter
, deci
) ; }
ostream
& operator
<< ( ostream out
, Myfloat
& w
)
{ out
<< w
. inter
<< '.' << w
. deci
;
}
istream
& operator
>> ( istream in
, Myfloat
& w
)
{ in
>> w
. inter
>> w
. deci
;
}
(4)賦值運算符重載用于對象數據的復制 用非類A類型的值為類A的對象賦值時(當然,這種情況下我們可以不提供相應的賦值運算符重載函數,而只提供相應的構造函數,如更有重載函數會優先調用重載后的賦值運算符)。 當用類A類型的值為類A的對象賦值,且類A的數據成員中含有指針的情況下,必須顯式提供賦值運算符重載函數。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std
;
class Myfloat
{ int inter
; int deci
;
public
: Myfloat ( int a
, int b
) : inter ( a
) , deci ( b
) { } Myfloat operator
+ ( Myfloat
const & temp
) const ; Myfloat operator
- ( Myfloat
const & temp
) const ; Myfloat operator
-- ( ) ; Myfloat operator
++ ( ) ; Myfloat operator
-- ( int ) ; Myfloat operator
++ ( int ) ; friend ostream
& operator
<< ( ostream out
, Myfloat
& w
) ; friend istream
& operator
>> ( istream in
, Myfloat
& w
) ; Myfloat
& operator
= ( const Myfloat
& temp
) ; Myfloat
& operator
= ( const int & w
) ;
} ;
Myfloat Myfloat
: : operator
+ ( Myfloat
const & temp
) const { return Myfloat ( inter
+ temp
. inter
, deci
+ temp
. deci
) ; }
Myfloat Myfloat
: : operator
- ( Myfloat
const & temp
) const { return Myfloat ( inter
- temp
. inter
, deci
- temp
. deci
) ; }
Myfloat Myfloat
: : operator
-- ( ) { return Myfloat ( inter
-- , deci
) ; }
Myfloat Myfloat
: : operator
++ ( ) { return Myfloat ( inter
++ , deci
) ; }
Myfloat Myfloat
: : operator
-- ( int ) { return Myfloat ( -- inter
, deci
) ; }
Myfloat Myfloat
: : operator
++ ( int ) { return Myfloat ( ++ inter
, deci
) ; }
ostream
& operator
<< ( ostream out
, Myfloat
& w
)
{ out
<< w
. inter
<< '.' << w
. deci
;
}
istream
& operator
>> ( istream in
, Myfloat
& w
)
{ in
>> w
. inter
>> w
. deci
;
}
Myfloat
& Myfloat
: : operator
= ( const Myfloat
& temp
)
{ inter
= temp
. inter
; deci
= temp
. deci
; return * this
;
}
Myfloat
& Myfloat
: : operator
= ( const int & w
)
{ inter
= w
; return * this
;
}
(二)基類與派生類
(1)繼承語法形式 :
class 派生類名:基類名表
{ 數據成員和成員函數聲明
} ;
基類類名表構成: 訪問控制 基類名1 訪問控制 基類名2… 繼承多各類時叫做多繼承,容易產生二義性,一般不用。
訪問控制有三種 public:公有繼承 private:私有繼承 protected:保護繼承 實例
class People { } class Student : public People
(2)派生類的生成過程
吸收基類成員:除構造和析構函數外 改造基類成員:通過在派生類中定義同名成員屏蔽基類成員在派生類中直接調用,仍可以基類指針調用同名成員 .添加新成員
(3)派生類特點
子類擁有父類除了父類構造和析構函數,所有的成員函數和成員變量; 2.子類就是一種特殊的父類; 子類對象可以當做父類的對象使用; 子類可以擁有父類沒有的方法和屬性。
(4)派生類中的靜態數據成員 基類中定義的靜態成員,將被所有派生類共享 2、基類初始化: (5)派生類的初始化
派生類構造函數聲明格式為: 派生類構造函數(變元表):基類(變元表)、對象成員1(變元表)
構造函數執行順序:基類——對象成員(類對象成員的初始化)——派生類 //一開始不理解,現在理解了 舉個栗子:
class People
{
protected
: string name
; string xb
;
public
: People ( string a
, string b
) : name ( a
) , xb ( b
) { }
} ;
class Cloth
{ string color
; int mysize
;
public
: Cloth ( string c
, int m
) : color ( c
) , mysize ( m
) { }
} ;
class Student
: public People
{ string id
; Cloth coat
;
public
: Student ( string id
, string name
, string xh
, string color
, int size
) : People ( name
, xb
) , coat ( color
, size
) , id ( id
) { }
} ;
執行順序跟我寫的順序一樣,但不是因為按這個順序寫的原因,就像成員變量初始化,也是按這定義順序初始化,與自己寫的初始化順序無關。 構造函數的執行順序:基類→對象成員→派生類; (6)派生類構造函數和析構函數的使用原則
基類的構造函數和析構函數不能繼承 派生類是否定義析構函數與所屬基類無關 如果基類沒有定義構造函數或是定義無參構造函數,派生類可以不定義構造函數。 如果基類無無參構造函數,派生類必須定義構造函數 如果派生類基類為連續基類繼承,每個派生類只負責直接基類的構造
(7)派生類析構函數
與構造函數執行順序相反,派生-----對象-----基類
(8)賦值兼容原則 這個規則可以簡述為能放基類的地方,放派生類一定可以使用,在程序中需要使用基類對象的地方都可以用公有派生類的對象代替。 例:
class Base{};
class Drived{};
Base demo1,Drived demo2;
demo1=demo2; //派生類對象可以賦值給基類對象:
Base&Bdemo3=demo2; //派生類對象可以初始化基類引用;
Base *Bpo=&demo2;//派生類對象可以賦給指向基類對象的指針;//多態實現的方法
主要是派生類中一定包含基類中所有成員,在使用中,一定可以找到對應成員。
賦值兼容應注意的問題:
指向基類的指針可以指向公有派生類的對象,但不允許指向它的私有派生類的對象。 允許將一個聲明為指向基類的指針指向其公有派生類對象,但是不能將一個聲明為指向派生類對象的指針指向基類對象。 聲明為指向基類對象的指針,當其指向公有派生類對象時,只能用它來直接訪問派生類中從基類繼承來的成員,而不能直接訪問公有派生類的定義的成員。
可以理解為派生類完全包含基類,指向基類的任何成員,都可以在公有派生類中找到對應的成員對象與之對應,如果是私有繼承,能找到但是不能訪問。但是派生類中有的對象,基類中不一定會有,所以不能這么操作。
(三)虛函數與多態:
(1)多態的概念: 一個接口,多種使用方法 (2)封裝的作用: 封裝可以是得代碼模塊化;繼承可以擴展已經存在的代碼,都是為了代代碼重用; **(3)多態的目的:**接口重用 (4)靜態聯編和動態聯編分別表示什么? 在編譯的時候能夠確定對象所調用的成員函數的地址則為靜態聯編,一般的調用方式; 動態聯編:指的是在程序運行的時候動態地進行,根據當時的情況來確定調用哪個同名函數,父類指針指向哪個子類,就調用哪個子類的同名函數,實際上是在運行的時候虛函數的實現;
#include <iostream>
using namespace std
; class Basic
{
public
: void oper1 ( ) { printf ( "1\n" ) ; } virtual
void oper2 ( ) { printf ( "2\n" ) ; }
} ;
class Direved
: public Basic
{
public
: void oper1 ( ) { printf ( "3\n" ) ; } void oper2 ( ) { printf ( "4\n" ) ; }
} ;
int main ( void )
{ Basic a
; Direved b
; Basic
* p
= & a
; p
-> oper1 ( ) ; p
-> oper2 ( ) ; p
= & b
; p
-> oper1 ( ) ; p
-> oper2 ( ) ; return 0 ;
}
運行結果過如下,重點關注是否為虛函數時函數調用的區別。 構成虛函數的必要條件: 函數返回類型一樣,參數表一樣,函數名一樣,同時需要關鍵字vitrual,缺一不可。
class Basic
{ vitrual
void p ( ) { 函數體
} ;
}
class Direved
: public Basic
{ void p ( ) { 函數體
} ;
}
class Basic
{ void p ( ) { 函數體
} ;
}
class Direved
: public Basic
{ void p ( ) { 函數體
} ;
}
class Basic
{ vitrual
void p ( ) { 函數體
} ;
}
class Direved
: public Basic
{ void p ( int a
) { 函數體
} ;
}
class Basic
{ vitrual
void p ( ) { 函數體
} ;
}
class Direved
: public Basic
{ double p ( ) { 函數體
} ;
}
(5)C++純虛函數 1.純虛函數是在基類中聲明的虛函數,它在基類中沒有定義,但要求任何派生類都要定義自己的實現方法。在基類中實現純虛函數的方法是在函數原型后加“=0”
virtual void funtion()=0
1、為了方便使用多態特性,我們常常需要在基類中定義虛擬函數。 2、在很多情況下,基類本身生成對象是不合情理的。例如,動物作為一個基類可以派生出老虎、孔雀等子類,但動物本身生成對象明顯不合常理。
Class animals
{ virtual
void mingjiao ( ) ;
{ }
}
為了解決上述問題,引入了純虛函數的概念
Class animals
{ virtual
void mingjiao ( ) = 0 ;
}
則編譯器要求在派生類中必須予以重寫以實現多態性。同時含有純虛擬函數的類稱為抽象類,它不能生成對象。這樣就很好地解決了上述兩個問題。 注意含有純虛函數的類,不能直接聲明對象!!!!!!!!
(6)多態性 實現的兩種方式 a、編譯時多態性:通過重載函數實現 b、運行時多態性:通過虛函數實現。
總結
以上是生活随笔 為你收集整理的C++ 重载运算符 继承 多态 (超详细) 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。