吉林大學陳偉-面向對象程序設計(基于C++語言講解)

表達式:
能作為左值表達式的,一定存在真實的物理空間。
lambda表達式。
指針:
1.空指針:NULL/nullptr
2.type* varName,以*號為界,右邊是變量,左邊是指向的東西
3.解引用
4.指針運算:int *p,p+n<<=>>偏移size(int)*n個單位,取數組元素a[k]就是*(a+k)
5.可以不初始化
數組:
1.int[5] a;
2.指針數組:int *array[5];
3.數組指針:int (*p)[5];//int[5] *p
引用:
1.是一個別名
2.對應的變量,對象必須存在
3.必須初始化
4.void(int& a,int& b);
#define 宏
1.無類型檢查
2可用于條件編譯
#define debug
int main(){
int a=100;
#ifdef debug
cout<<a<<endl;
do1();
#else
do2();
#endif
}
}
3.特殊應用:
cout<<_LINE_<<endl;當前語句所在行數
cout<<_FILE_<<endl;當前語句所在文件名
cout<<_FUNCTION_<<endl;當前語句所在函數
命名常量:
1.格式:const int CAED_COUNT=54;
2.命名常量可以放在頭文件里,不會重復定義,進行常量折疊(直接替換)
const和指針:
1.const int *pt=&a與int const *pt=&a等價,pt可以指向任何東西,但指向的東西不可以通過pt修改,別的指針可以改
2int *p=pt;//報錯
3.T * const pt= &a;必須初始化;指針指向不能該,可以通過指針改變指向的內容;

4.char * str="hello world";等價于const char * str="hello world";
const和引用
1.int b=100;
const int& aa=b;//不可以通過修改b
const int& bb=1;//正確,但前面必須加const
2.const引用主要用于函數參數傳遞
函數聲明:
1.:

成員函數有可能加const
2:

函數調用的過程:
1.記錄調用現場
2.在棧中建立局部變量
3.恢復調用現場
4.誰來負責清棧;
調用者負責:可處理變參和固定參數函數
被調用者負責:只能處理固定參數函數
調用約定:

常見windows所有的API函數都是標準調用(_stdcall)
_thiscall調用是所有面向對象語言的成員函數所采用的調用約定,隱藏一個默認參數this指針
函數重載:
多個同名函數,但它們具有不同參數類型,參數順序,參數個數,const修飾,異常說明數時,可以同時存在,稱為函數重載。
int Func();
int Func(int);
int Func(int,int);
int Func(int,int)const;
int Func(int)throw();
int Func(int)throw(int,MyE,YourE);
int Func(MyClass obj);

名字重整:由編譯器在函數名字的基本信息之上,添加必要的參數信息,形成新的函數名字,用于區(qū)分不同的重載函數
例:void Fun(int)經重整后,生成類似_Fun_int的新函數名
缺點:一個程序中難以確定另一個程序中經重整的函數名
禁止函數重載:
extern "C"{//以下函數按c語言形式處理,不允許名字重載
int Fun();
int Func(int);
int OtherFun();
}
extern "C" void MyFunc(int);
函數的參數列表:
1.缺省參數:應該在函數原型中提供,若無函數原型,才在定義中給出,一般只提供一次
2.定義中的參數,可以無名(一般用于函數重載)


函數的返回:
1.按值返回:
默認返回int;void;內置類型(基本類型,派生類型);返回普通內置類型基本都是const;自定義類型(類,結構);
2.返回指針:T*f();等價于T* const f();
但不等價于const T* f();
3.返回引用:

int & max(int& a,int& b){return a>b?a:b;}
int a=5,b=7;
max(a,b)=4;//把兩者較大的改為4
類型的抽象表示:
ADT:與具體表示無關
與現實世界無關
任意性和無窮性
a ADT:
name{
數據:
關系:
操作:
}
操作是區(qū)分類型的關鍵
類型的表示及定義:

類的定義可采用前置聲明(避免循環(huán)定義,降低文件依賴性)
類的成員:
1數據成員:

struct和class用引用也可以
2成員函數:
類和對象:
classname objectname;
classname *pobj=new classname;

向對象obj發(fā)送消息f,f的參數是20。
向對象o2發(fā)送消息f,f的參數是99。
通過指針向對象obj發(fā)送消息f,f的參數是5。
對象的存儲:

判斷兩個對象是不是同一個對象是通過判斷地址是否一致完成的
對齊方式:按一個字節(jié)對齊,按兩個字節(jié)對齊,按四個字節(jié)對齊,在編譯時設定。
靜態(tài)數據成員存儲在程序區(qū)。
成員函數的實現:


this指針是非靜態(tài)成員函數隱含的第一個參數,用來指明被實例化的當前對象。
this指針:


對于Ultraman& Ultraman::fight(Monster& m);函數,考慮以下幾種變體:
1.若返回值為void,則無法連續(xù)擊打小怪獸
2若返回值不加&,輸出的happiness是不一樣的,但不是同一個Ultraman擊打的
外聯實現和內聯實現:
外聯實現:

類里寫函數聲明,類外寫實現。
內聯實現:

1.類里直接給實現(默認前面有個inline)
2.類外加inline關鍵字
3.建議編譯器在調用處直接展開函數代碼

使用內聯函數的不足:
可能會產生類之間的依賴性
解決方式:
1前置聲明
2外聯實現


訪問控制:
pubblic:任何類都可以訪問,類外可以訪問
private:本類(不是本對象)或友元可以訪問

封裝與信息隱蔽:

封裝與信息隱蔽的作用:

常成員函數:


即使func 3()大括號的內容為空,也會報錯。因為func3()有能力修改對象的成員變量。
不帶const函數隱含的的第一格變量為T* const this.

定義函數本意時未打算修改,則應該加const.
實例變量實例方法類變量類方法:


1.常成員函數可以修改類變量,因為類變量不屬于當前對象,它存儲在程序區(qū)(不是this指針所指)。
2.類變量必須顯式初始化。typename classname:: var= ;
3.類方法只能訪問類變量類方法,不能訪問實例變量和實例方法。

8.1自定義構造函數

在沒有explicit的情況下,發(fā)f(100)會根據100,Name(int)進行隱式調用,即會把100直接轉化為Name(100)的對象,但是在由explicit的情況下,只允許顯式調用,f(100)會直接報錯。

私有自定義構造函數允許類內函數進行調用
兩者都只允許實例化一個對象,但是指針的形式更常用。

缺省的構造函數
無參數的,public的
只有在用戶沒有提供自定義構造函數的情況下,才由編譯器提供

右邊三種認為提供了自定義構造函數
對象的初始化

1.程序執(zhí)行到構造函數大括弧時,對象已經創(chuàng)建,大括弧里只是對數據成員賦值。所以,在大括弧內對const數據成員賦值就會出錯。
2.賦值初始化只是對象初始化的一種形式
3.

4.初始化列表:
class A{
public:
??A(int a){
????_a = a;//有參構造,沒有默認構造函數
??}
private:
??int _a;
};
class Student{
public:
??Student(int a, int age)
????:_aa(a)
????,_age(age)
????,_no(001)
????{}//必須在初始化列表中進行初始化
private:
??A _aa;//自定義類型,且沒有自己的默認構造函數
??int& _age;//引用
??const int _no//const的成員變量
};
析構函數:

1構造函數和析構函數都有this指針
2構造函數和析構函數都不能加const
3右邊的例子析構函數可給可不給
4在Card析構時,由于desc是對象,所以調用desc的析構函數
構造和析構函數的訪問:


delete pa時,調用pa的析構函數~A(),大括弧執(zhí)行完畢后,執(zhí)行b1,b2的析構函數。
對象的拷貝:

紅色部分都要進行拷貝復制


注意對象拷貝構造和賦值的區(qū)別
拷貝構造時從無到有創(chuàng)建一個對象,在該語句前,該對象是不存在的
如上圖右側,a1=a2即為賦值,B b2(b1);B b3=b1;都是拷貝構造;
缺省拷貝構造函數:

淺拷貝是按bit位拷貝
淺拷貝:

淺拷貝只對對象內的數據成員進行拷貝。由于靜態(tài)數據成員是屬于類的,不屬于對象,所以不在淺拷貝的考慮范圍之內