笔记 黑马程序员C++教程从0到1入门编程——核心编程
目錄
1 內(nèi)存分區(qū)模型
程序運(yùn)行前
01 代碼區(qū)
02 全局區(qū)
程序運(yùn)行后
03 棧區(qū)
04 堆區(qū)
05 new操作符
2 引用
06 引用的基本使用
07 引用注意事項(xiàng)
08 引用做函數(shù)參數(shù)
09 引用做函數(shù)返回值
10 引用的本質(zhì)
11 常量引用
3 函數(shù)提高
12函數(shù)默認(rèn)參數(shù)
13 函數(shù)占位參數(shù)
14 函數(shù)重載
4 類(lèi)和對(duì)象
封裝
16 封裝的意義 屬性和行為作為整體
對(duì)象特性:對(duì)象的初始化和清理
23 構(gòu)造函數(shù)和析構(gòu)函數(shù)
24 構(gòu)造函數(shù)的分類(lèi)和調(diào)用
?25 拷貝構(gòu)造函數(shù)調(diào)用時(shí)機(jī)
26 構(gòu)造函數(shù)調(diào)用規(guī)則
27 深拷貝和淺拷貝
28 初始化列表
29 類(lèi)對(duì)象作為類(lèi)成員
30 靜態(tài)成員
對(duì)象特性:C++對(duì)象模型和this指針
32 成員變量和成員函數(shù)分開(kāi)存儲(chǔ)
33 this指針
34 空指針訪(fǎng)問(wèn)成員函數(shù)
35 const修飾成員函數(shù)
友元
36 全局函數(shù)做友元
37 友元類(lèi)
38 成員函數(shù)做友元
C++運(yùn)算符重載
39 加號(hào)運(yùn)算符重載?
40 左移運(yùn)算符重載
41 遞增運(yùn)算符重載
42 賦值運(yùn)算符重載
43 關(guān)系運(yùn)算符重載
44 函數(shù)調(diào)用運(yùn)算符重載
繼承
45 基本語(yǔ)法
46 繼承方式
47 繼承中的對(duì)象模型
48 構(gòu)造和析構(gòu)順序
49 同名成員處理
50 同名靜態(tài)成員處理
51 多繼承語(yǔ)法
52 菱形繼承問(wèn)題以及解決方法
多態(tài)
53 多態(tài)的基本語(yǔ)法
54 多態(tài)的原理剖析
56 純虛函數(shù)和抽象函數(shù)
58 虛析構(gòu)和純虛析構(gòu)
5 文件操作
文本文件
143 寫(xiě)文件
144 讀文件
二進(jìn)制文件
145 寫(xiě)文件
146 讀文件
1 內(nèi)存分區(qū)模型
程序運(yùn)行前
程序運(yùn)行運(yùn)行前,編譯后:
01 代碼區(qū)
代碼區(qū):存放函數(shù)的二進(jìn)制代碼,有操作系統(tǒng)進(jìn)行管理
【共享,只讀】?
02 全局區(qū)
全局區(qū):存放全局變量,靜態(tài)變量(static),常量(字符串常量和const修飾的全局常量(全局常量))
【在程序結(jié)束后由操作系統(tǒng)釋放】
//不在全局區(qū)的數(shù)據(jù):局部變量、const修飾的局部變量(局部常量)?
程序運(yùn)行后
03 棧區(qū)
棧區(qū):由編譯器自動(dòng)分配釋放,存放函數(shù)的形參,局部變量等
//不要返回局部變量的地址,棧區(qū)開(kāi)辟的數(shù)據(jù)由編譯器自動(dòng)釋放
04 堆區(qū)
堆區(qū):由程序員分配和釋放,若程序員不釋放,系統(tǒng)結(jié)束時(shí)由操作系統(tǒng)回收
//new可以創(chuàng)建堆區(qū)數(shù)據(jù),返回的是創(chuàng)建的堆區(qū)的地址,要用指針接收
05 new操作符
? int* arr = new int[10];//堆區(qū)開(kāi)辟數(shù)組
delete[] arr;//釋放數(shù)組
2 引用
06 引用的基本使用
作用:給變量起別名
語(yǔ)法:數(shù)據(jù)類(lèi)型 &別名=原名;
07 引用注意事項(xiàng)
引用必須初始化
引用初始化后不可以改變
08 引用做函數(shù)參數(shù)
引用傳遞讓形參修飾實(shí)參,簡(jiǎn)化指針修改實(shí)參?
通過(guò)引用參數(shù)產(chǎn)生的效果同按地址傳遞是一樣的,引用的語(yǔ)法更清楚簡(jiǎn)單
//引用傳遞 void mySwap(int &a,int &b) {int temp = a;a = b;b = temp; }int main() {int a = 1;int b = 2;cout << "a=" << a << endl;//1cout << "b=" << b << endl;//2mySwap(a, b);cout << "swap a=" << a << endl;//2cout << "swap b=" << b << endl;//1system("pause");return 0; }09 引用做函數(shù)返回值
作用:引用是可以作為函數(shù)的返回值存在的
注意:不要返回局部變量引用
用法:函數(shù)返回值是引用時(shí),函數(shù)調(diào)用可以作為左值
//返回局部變量引用,非法操作 int& test01() {int a = 10;//局部變量存放在棧區(qū)return a; }//返回靜態(tài)變量引用,可以執(zhí)行 int& test02() {static int a = 10;//靜態(tài)變量,存放在全局區(qū),系統(tǒng)釋放return a; }int main() {//1.不要返回局部變量的引用int& ref = test01();cout << ref << endl;//第一次正確,因?yàn)榫幾g器做了保留//cout << ref << endl;//第二次錯(cuò)誤,因?yàn)閍的內(nèi)存已經(jīng)釋放int& ref2 = test02();cout << ref2 << endl;//10cout << ref2 << endl;//10cout << ref2 << endl;//10//2.如果函數(shù)的返回值是引用,這個(gè)函數(shù)的調(diào)用可以作為左值進(jìn)行賦值操作test02() = 1000;cout << ref2 << endl;//1000cout << ref2 << endl;//1000system("pause");return 0; }10 引用的本質(zhì)
引用的本質(zhì)在C++內(nèi)部實(shí)現(xiàn)是一個(gè)指針常量
(指針的指向是不可以修改,指針指向的值是可以改動(dòng))
11 常量引用
用來(lái)修飾形參,防止誤操作
(在函數(shù)形參列表中,可以加const修飾形參,防止形參改變實(shí)參)
void showValue(const int& val)//函數(shù)中利用常量引用防止誤操作修改實(shí)參 {cout << val; } int main() {//常量引用:用來(lái)修飾形參,防止誤操作int a = 10;//int& ref = 10;//err,引用必須引一塊合法的內(nèi)存空間const int& ref = 10;//編譯器幫修改為int temp=10;int &ref=temp;//ref = 20;//加入const之后,變?yōu)橹蛔x,不可修改int a = 100;showValue(a);system("pause");return 0; }3 函數(shù)提高
12函數(shù)默認(rèn)參數(shù)
語(yǔ)法:返回值類(lèi)型 函數(shù)名(形參=默認(rèn)值){ }
- C++中函數(shù)的形參列表中的形參是可以有默認(rèn)值的
- 如果有傳入數(shù)據(jù),就用傳入的數(shù)據(jù),如果沒(méi)有就用默認(rèn)值
- 如果某個(gè)位置已經(jīng)有了默認(rèn)參數(shù),那么這個(gè)位置之后,從左到右都必須有默認(rèn)值
- 聲明和實(shí)現(xiàn)只能有一個(gè)有默認(rèn)參數(shù);如果函數(shù)聲明有默認(rèn)參數(shù),函數(shù)實(shí)現(xiàn)就不能有默認(rèn)參數(shù)
13 函數(shù)占位參數(shù)
C++中函數(shù)形參列表里可以有占位參數(shù),用來(lái)占位,調(diào)用函數(shù)時(shí)必須填補(bǔ)該位置
語(yǔ)法:返回值類(lèi)型 函數(shù)名(數(shù)據(jù)類(lèi)型){}
?? ?//占位參數(shù)還可以有默認(rèn)參數(shù) (int=10),有默認(rèn)值時(shí),調(diào)用時(shí)可以不用傳值
14 函數(shù)重載
函數(shù)名可以相同,提高復(fù)用性
滿(mǎn)足條件:
函數(shù)的返回值不可以作為函數(shù)重載的條件
注意事項(xiàng):
4 類(lèi)和對(duì)象
面向?qū)ο笕筇匦?#xff1a;封裝、繼承、多態(tài)
萬(wàn)物是對(duì)象,有屬性和行為
具有相同性質(zhì)的對(duì)象,可以抽象為類(lèi)
封裝
16 封裝的意義 屬性和行為作為整體
//設(shè)計(jì)一個(gè)圓類(lèi),求周長(zhǎng)
const double PI = 3.14;class Circle {//訪(fǎng)問(wèn)權(quán)限:公共權(quán)限 public ://屬性int m_r;//半徑//行為:獲取圓的周長(zhǎng)double calculateZC(){return 2 * PI * m_r;} };//實(shí)例化(通過(guò)一個(gè)類(lèi),創(chuàng)建一個(gè)對(duì)象的過(guò)程)Circle c1;//通過(guò)圓類(lèi),創(chuàng)建具體的圓(對(duì)象)c1.m_r = 10;//給圓的對(duì)象的屬性賦值cout << "圓的周長(zhǎng)為:" << c1.calculateZC() << endl;實(shí)例化:通過(guò)一個(gè)類(lèi),創(chuàng)建一個(gè)對(duì)象的過(guò)程
類(lèi)中的屬性和行為,統(tǒng)稱(chēng)為成員
- 屬性 ?成員屬性 成員變量
- 行為 成員函數(shù) 成員方法
類(lèi)在設(shè)計(jì)時(shí),可以把屬性和行為放在不同的權(quán)限下,加以控制
18?三種訪(fǎng)問(wèn)權(quán)限
//公共權(quán)限 public? ? ? ? ? 成員類(lèi)內(nèi)可以訪(fǎng)問(wèn),類(lèi)外可以訪(fǎng)問(wèn)
//保護(hù)權(quán)限 protected? ? 類(lèi)內(nèi)可以訪(fǎng)問(wèn),類(lèi)外不可以訪(fǎng)問(wèn)? ? ? ? ? ? 兒子可以訪(fǎng)問(wèn)父親中的保護(hù)內(nèi)容
//私有權(quán)限 private? ? ? ? 類(lèi)內(nèi)可以訪(fǎng)問(wèn),類(lèi)外不可以訪(fǎng)問(wèn)? ? ? ? ? ? 兒子不可以訪(fǎng)問(wèn)父親中的私有內(nèi)容
19 struct和class的區(qū)別:
默認(rèn)的訪(fǎng)問(wèn)權(quán)限不同?
struct默認(rèn)權(quán)限是? 公共? public
class默認(rèn)權(quán)限是? ?私有? private
20 成員屬性設(shè)置為私有的優(yōu)點(diǎn)
//設(shè)計(jì)立方體類(lèi)
//創(chuàng)建立方體類(lèi) class Cube { public:void setL(int l){m_L = l;}void setW(int w){m_W = w;}void setH(int h){m_H = h;}int getL(){return m_L ;}int getW(){return m_W;}int getH(){return m_H;}int calculateS(){return 2 * m_L * m_W + 2 * m_H * m_W + 2 * m_L * m_H;}int calculateV(){return m_L * m_W * m_H;}//利用局部函數(shù)判斷是否相等bool isSamebyclass(Cube& c){if (getL() == c.getL() && getW() == c.getW() && getH() == c.getH())return true;elsereturn false;} private:int m_L;int m_W;int m_H; };//利用全局函數(shù)判斷兩個(gè)立方體是否相等 bool isSame(Cube& c1, Cube& c2) {if (c1.getL() == c2.getL() && c1.getW() == c2.getW() && c1.getH() == c2.getH())return true;elsereturn false; }int main() {Cube c1;c1.setL(10);c1.setW(10);c1.setH(10);cout<<"面積為"<<c1.calculateS()<<endl;cout << "體積為" << c1.calculateV() << endl;Cube c2;c2.setL(11);c2.setW(10);c2.setH(10);cout << "面積為" << c2.calculateS() << endl;cout << "體積為" << c2.calculateV() << endl;//利用全局函數(shù)判斷bool ret=isSame(c1,c2);if (ret)cout << "相等" << endl;elsecout << "不相等" <<endl;//利用局部函數(shù)判斷bool ret1 = c1.isSamebyclass(c2);if (ret1)cout << "相等" << endl;elsecout << "不相等" << endl;system("pause");return 0; }//判斷點(diǎn)和圓的關(guān)系?
在類(lèi)中可以讓另一個(gè)類(lèi) 作為本類(lèi)中的成員
可以把一個(gè)類(lèi)拆在不同文件中 .h聲明 .cpp實(shí)現(xiàn)
對(duì)象特性:對(duì)象的初始化和清理
每個(gè)對(duì)象也會(huì)有初識(shí)設(shè)置以及對(duì)象銷(xiāo)毀前的清理數(shù)據(jù)的設(shè)置
23 構(gòu)造函數(shù)和析構(gòu)函數(shù)
編譯器自動(dòng)調(diào)用,完成對(duì)象初始化和清理工作
- 構(gòu)造函數(shù):創(chuàng)建對(duì)象時(shí)對(duì)象的成員屬性賦值
- 析構(gòu)函數(shù):對(duì)象銷(xiāo)毀前,清理工作
構(gòu)造函數(shù):類(lèi)名(){}
析構(gòu)函數(shù):~類(lèi)名(){}
24 構(gòu)造函數(shù)的分類(lèi)和調(diào)用
構(gòu)造函數(shù)分類(lèi):
按照參數(shù):有參構(gòu)造和無(wú)參構(gòu)造(默認(rèn)構(gòu)造)
按照類(lèi)型:普通構(gòu)造和拷貝構(gòu)造
調(diào)用方式:
1.括號(hào)法2.顯示法3.隱式轉(zhuǎn)換法
?25 拷貝構(gòu)造函數(shù)調(diào)用時(shí)機(jī)
拷貝構(gòu)造函數(shù)調(diào)用時(shí)機(jī)三種情況:
26 構(gòu)造函數(shù)調(diào)用規(guī)則
調(diào)用規(guī)則:
如果我們寫(xiě)了有參構(gòu)造函數(shù),編譯器就不再提供默認(rèn)構(gòu)造,依然提供拷貝構(gòu)造
如果我們寫(xiě)了拷貝構(gòu)造函數(shù),編譯器就不再提供其他普通構(gòu)造函數(shù)?
27 深拷貝和淺拷貝
淺拷貝:簡(jiǎn)單的復(fù)制拷貝操作
淺拷貝帶來(lái)的問(wèn)題就是堆區(qū)的內(nèi)存重復(fù)釋放
深拷貝:在堆區(qū)重新申請(qǐng)空間,進(jìn)行拷貝操作
//如果屬性有在堆區(qū)開(kāi)辟的,一定要自己提供拷貝構(gòu)造函數(shù),防止淺拷貝帶來(lái)的問(wèn)題
28 初始化列表
//初始化列表Person(int a,int b,int c) :m_A(a), m_B(b), m_C(c){} //屬性賦初值 Person p(31,20,10);29 類(lèi)對(duì)象作為類(lèi)成員
類(lèi)中的成員可以是另一個(gè)類(lèi)的對(duì)象,我們稱(chēng)該成員為對(duì)象成員
- 當(dāng)其他類(lèi)對(duì)象作為本類(lèi)成員,構(gòu)造時(shí)候先構(gòu)造類(lèi)對(duì)象,再構(gòu)造自身
- 當(dāng)其他類(lèi)對(duì)象作為本類(lèi)成員,析構(gòu)時(shí)候先析構(gòu)自身,再析構(gòu)類(lèi)對(duì)象
構(gòu)造順序與析構(gòu)順序相反
class Phone { public:Phone(string pName){m_PName = pName;cout << "phone的構(gòu)造函數(shù)調(diào)用" << endl;}~Phone(){cout << "phone的析構(gòu)函數(shù)調(diào)用" << endl;}string m_PName; }; class Person { public:Person(string name, string pName):m_Name(name),m_phone(pName){cout << "person的構(gòu)造函數(shù)調(diào)用" << endl;}~Person(){cout << "person的析構(gòu)函數(shù)調(diào)用" << endl;}string m_Name;Phone m_phone; };30 靜態(tài)成員
靜態(tài)成員變量:
- 所有對(duì)象共享同一份數(shù)據(jù)
- 在編譯階段分配內(nèi)存(程序運(yùn)行前-全局區(qū))
- 類(lèi)內(nèi)聲明,類(lèi)外初始化
靜態(tài)成員變量,不屬于某個(gè)對(duì)象上,所有對(duì)象都共享同一份數(shù)據(jù)?
有兩種訪(fǎng)問(wèn)方式:
靜態(tài)成員變量有訪(fǎng)問(wèn)權(quán)限,類(lèi)外訪(fǎng)問(wèn)不到私有靜態(tài)成員變量
31 靜態(tài)成員函數(shù)
- 所有對(duì)象共享同一個(gè)函數(shù)
- 靜態(tài)成員函數(shù)只能訪(fǎng)問(wèn)靜態(tài)成員變量
//兩種訪(fǎng)問(wèn)方式:通過(guò)對(duì)象,通過(guò)類(lèi)名
//靜態(tài)成員函數(shù)也是有訪(fǎng)問(wèn)權(quán)限的,類(lèi)外訪(fǎng)問(wèn)不到私有的靜態(tài)成員函數(shù)
對(duì)象特性:C++對(duì)象模型和this指針
32 成員變量和成員函數(shù)分開(kāi)存儲(chǔ)
只有非靜態(tài)成員變量 屬于對(duì)象上的數(shù)據(jù)
??空對(duì)象占用內(nèi)存空間為:1
?? ?//C++編譯器會(huì)給每個(gè)空對(duì)象也分配一個(gè)字節(jié)空間,是為了區(qū)分空對(duì)象占內(nèi)存的位置
?? ?//每個(gè)空對(duì)象也應(yīng)該有一個(gè)獨(dú)一無(wú)二的內(nèi)存地址
33 this指針
this指針:指向被調(diào)用的成員函數(shù)所屬的對(duì)象
this指針是隱含每一個(gè)非靜態(tài)成員函數(shù)內(nèi)的一種指針
this指針不需要定義,直接使用
用途:
//當(dāng)形參和成員變量同名時(shí),可用this指針來(lái)區(qū)分
//在類(lèi)的非靜態(tài)成員函數(shù)中返回對(duì)象本身,可使用return *this
34 空指針訪(fǎng)問(wèn)成員函數(shù)
C++中允許空指針調(diào)用成員函數(shù),也要注意有沒(méi)有用到this指針
//如果用到this指針,需要判斷保證代碼的健壯性
35 const修飾成員函數(shù)
常函數(shù)
成員函數(shù)后加const稱(chēng)為常函數(shù)
//常函數(shù)內(nèi)不可以修改成員屬性(指針指向的值不能修改)
//成員屬性聲明時(shí)加關(guān)鍵字mutable后,在常函數(shù)中依然可以修改
常對(duì)象
聲明對(duì)象前加const稱(chēng)為常對(duì)象
//常對(duì)象只能調(diào)用常函數(shù)
友元
36 全局函數(shù)做友元
class Building {friend void goodgay(Building* builiding);//goodgay是Building好朋友,可以訪(fǎng)問(wèn)Builing中私有成員 public:Building(){m_SittingRoom = "客廳";m_BedRoom = "臥室";} public:string m_SittingRoom;private:string m_BedRoom;}; //全局函數(shù) void goodgay(Building *builiding) {cout << "全局函數(shù)正在訪(fǎng)問(wèn):" << builiding->m_BedRoom << endl;cout << "全局函數(shù)正在訪(fǎng)問(wèn):" << builiding->m_SittingRoom << endl; }37 友元類(lèi)
friend class goodgay;//goodgay類(lèi)是本類(lèi)的好朋友,可以訪(fǎng)問(wèn)本類(lèi)中私有的成員38 成員函數(shù)做友元
friend void Goodgay::visit01();//goodgay類(lèi)下的visit成員函數(shù)作為本類(lèi)的好朋友,可以訪(fǎng)問(wèn)私有成員C++運(yùn)算符重載
運(yùn)算符重載:對(duì)已有運(yùn)算符重新進(jìn)行定義,賦予另一種功能,以適應(yīng)不同的數(shù)據(jù)類(lèi)型
39 加號(hào)運(yùn)算符重載?
作用:實(shí)現(xiàn)兩個(gè)自定義數(shù)據(jù)類(lèi)型相加的運(yùn)算
//對(duì)于內(nèi)置的數(shù)據(jù)類(lèi)型表達(dá)式運(yùn)算符是不可能改變的
//不要濫用運(yùn)算符重載
40 左移運(yùn)算符重載
輸出左移運(yùn)算符配合友元可以實(shí)現(xiàn)輸出自定義數(shù)據(jù)類(lèi)型
class Person {friend ostream& operator<<(ostream& cout, Person& p); public:Person(int a, int b){m_A = a;m_B = b;} private://不會(huì)利用成員函數(shù)重載左移運(yùn)算符<<,因?yàn)闊o(wú)法實(shí)現(xiàn)cout在左側(cè)int m_A;int m_B;};//只能利用全局函數(shù)重載左移運(yùn)算符 ostream& operator<<(ostream &cout,Person &p)//本質(zhì)是operator<<(cout,p) 簡(jiǎn)化cout<<p {cout << "m_A=" << p.m_A << endl;cout << "m_B=" << p.m_B << endl;return cout;//為了可以無(wú)限往后追加輸出 } void test01() {Person p(10, 10);cout << p <<"hello"<< endl;; }41 遞增運(yùn)算符重載
通過(guò)重載遞增運(yùn)算符,實(shí)現(xiàn)自己的整形數(shù)據(jù)
前置遞增返回參數(shù),后置遞增返回值??
//++//自定義整形 class MyInteger {friend ostream& operator<<(ostream& cout, MyInteger myint); public:MyInteger(){m_Num = 0;}//重載++運(yùn)算符//1.重載前置++ MyInteger& operator++()//返回引用是為了一直對(duì)一個(gè)數(shù)據(jù)進(jìn)行遞增操作{//先進(jìn)行++運(yùn)算m_Num++;//再將自身返回return *this;}//2.重載后置++ //返回的是值,因?yàn)榉祷氐氖蔷植孔兞縈yInteger operator++(int)//int代表占位參數(shù),可以用于區(qū)分前置和后置遞增,編譯器會(huì)認(rèn)為這是后置遞增重載{//先記錄當(dāng)時(shí)結(jié)果MyInteger temp = *this;//后遞增m_Num++;//再返回之前記錄的結(jié)果return temp;} private:int m_Num; };//重載左移運(yùn)算符 ostream& operator<<(ostream& cout, MyInteger myint) {cout << myint.m_Num << endl;return cout; }void test01() {MyInteger myint;cout << ++(++myint) << endl; } void test02() {MyInteger myint;cout << myint++ << endl;cout << myint << endl; }test01();test02();42 賦值運(yùn)算符重載
Person& operator=(Person& p){//編譯器提供的是淺拷貝//m_Age=p.m_Age;//應(yīng)該先判斷有屬性在堆區(qū),如果有先釋放干凈,然后再深拷貝if (m_Age != NULL){delete m_Age;m_Age = NULL;}m_Age=new int(*p.m_Age);//深拷貝return *this;}43 關(guān)系運(yùn)算符重載
//重載==bool operator==(Person& p){if (this->m_Age == p.m_Age && this->m_Name == p.m_Name){return true;}else false;}//重載!=bool operator!=(Person& p){if (this->m_Age == p.m_Age && this->m_Name == p.m_Name){return false;}else true;}44 函數(shù)調(diào)用運(yùn)算符重載
函數(shù)調(diào)用運(yùn)算符()也可以重載
由于重載后使用的方式非常像函數(shù)的調(diào)用,因此稱(chēng)為仿函數(shù)
仿函數(shù)沒(méi)有固定的寫(xiě)法,非常靈活
//打印輸出 class MyPrint { public://重載函數(shù)調(diào)用運(yùn)算符void operator()(string test){cout << test << endl;} }; void test01() {MyPrint myPrint;myPrint("hello");//由于使用起來(lái)類(lèi)似于函數(shù)調(diào)用,稱(chēng)為仿函數(shù) } //仿函數(shù)非常靈活,沒(méi)有固定的寫(xiě)法 //加法類(lèi) class MyAdd { public:int operator()(int num1, int num2){return num1 + num2;} }; void test02() {MyAdd myadd;int ret = myadd(100, 200);cout << ret << endl;//匿名函數(shù)對(duì)象 //MyAdd()cout << MyAdd()(100, 200) << endl; } int main() {test01();test02();return 0; }繼承
45 基本語(yǔ)法
繼承的好處:減少重復(fù)代碼
語(yǔ)法: class 子類(lèi):繼承方式 父類(lèi)
? ? ? ? ? ? class A : publib B
????????????A類(lèi),子類(lèi)也稱(chēng)為派生類(lèi)
????????????B類(lèi),父類(lèi)也稱(chēng)為基類(lèi)
派生類(lèi)中的成員,包含兩大部分:一類(lèi)是從基類(lèi)繼承過(guò)來(lái)的,一類(lèi)是自己增加的成員
從基類(lèi)繼承過(guò)來(lái)的表現(xiàn)其共性,而新增的成員體現(xiàn)其個(gè)性
46 繼承方式
?繼承的三種方式:
- 公共繼承
- 保護(hù)繼承
- 私有繼承
47 繼承中的對(duì)象模型
class Base { public:int a; protected:int b; private:int c;};class Son :public Base { public:int d;};void test01() {//父類(lèi)中所有靜態(tài)成員屬性都會(huì)被子類(lèi)繼承下去//父類(lèi)中私有成員屬性是被編譯器給隱藏了,因此是訪(fǎng)問(wèn)不到,但是確實(shí)被繼承下去了cout << "size of Son=" << sizeof(Son) << endl;//16 }利用開(kāi)發(fā)人員命令提示工具(Developer Command Prompt for VS 2019)查看對(duì)象模型
//跳轉(zhuǎn)盤(pán)符 F:
//跳轉(zhuǎn)文件路徑 cd 具體路徑下
//查看命令 cl /d1 reportSingleClassLayout類(lèi)名 文件名
? ? ? ? ? ? ? ? F:\C++-code\0421繼承>cl /d1 reportSingleClassLayoutSon "129對(duì)象基本模型.cpp"?
48 構(gòu)造和析構(gòu)順序
子類(lèi)繼承父類(lèi)后,當(dāng)創(chuàng)建子類(lèi)對(duì)象,也會(huì)調(diào)用父類(lèi)的構(gòu)造函數(shù)
繼承中的構(gòu)造和析構(gòu)的順序:
先構(gòu)造父類(lèi),再構(gòu)造子類(lèi);析構(gòu)順序與構(gòu)造順序相反
49 同名成員處理
當(dāng)子類(lèi)與父類(lèi)出現(xiàn)同名的成員,如何通過(guò)子類(lèi)對(duì)象,訪(fǎng)問(wèn)到其中的同名數(shù)據(jù):
1.訪(fǎng)問(wèn)子類(lèi)同名成員,直接訪(fǎng)問(wèn)即可
2.訪(fǎng)問(wèn)父類(lèi)同名成員,需要加作用域
- 如果子類(lèi)中出現(xiàn)和父類(lèi)中同名的成員函數(shù),子類(lèi)的同名成員會(huì)隱藏掉父類(lèi)中所有同名成員函數(shù)(包括重載版本)
- 如果想訪(fǎng)問(wèn)到父類(lèi)中被隱藏的同名成員函數(shù),需要加作用域?
50 同名靜態(tài)成員處理
?同名靜態(tài)成員處理方式和非靜態(tài)處理方式一樣,只不過(guò)有兩種訪(fǎng)問(wèn)方式(通過(guò)對(duì)象和通過(guò)類(lèi)名)
class Base{public:static int m_A;static void func(){cout << "Base 的func的調(diào)用" << endl;}};int Base::m_A = 100;class Son :public Base{public:static int m_A;static void func(){cout << "Son 的func的調(diào)用" << endl;}};int Son::m_A = 200;void test01(){//通過(guò)對(duì)象訪(fǎng)問(wèn)Son s;cout << "Son的m_A=" << s.m_A << endl;cout << "Base的m_A=" << s.Base::m_A << endl;//通過(guò)類(lèi)名訪(fǎng)問(wèn)cout << Son::m_A << endl;cout << Base::m_A << endl;cout << Son::Base::m_A << endl;//第一個(gè)::代表通過(guò)類(lèi)名方式訪(fǎng)問(wèn),第二個(gè)::代表訪(fǎng)問(wèn)父類(lèi)作用域下的m_A}void test02(){//通過(guò)對(duì)象訪(fǎng)問(wèn)Son s;s.func();s.Base::func();//通過(guò)類(lèi)名訪(fǎng)問(wèn)Son::func();Son::Base::func();}51 多繼承語(yǔ)法
C++允許一個(gè)類(lèi)繼承多個(gè)類(lèi)
語(yǔ)法:class 子類(lèi):繼承方式 父類(lèi)1,繼承方式 父類(lèi)2
//多繼承可能會(huì)引發(fā)父類(lèi)中有同名成員出現(xiàn),需要加作用域
//開(kāi)發(fā)中不建議用多繼承
52 菱形繼承問(wèn)題以及解決方法
菱形繼承、鉆石繼承:
- 兩個(gè)派生類(lèi)繼承同一個(gè)類(lèi)
- 又有某個(gè)類(lèi)同時(shí)繼承兩個(gè)派生類(lèi)?
多態(tài)
53 多態(tài)的基本語(yǔ)法
動(dòng)態(tài)多態(tài)滿(mǎn)足條件:
動(dòng)態(tài)多態(tài)使用:父類(lèi)的指針或引用 指向子類(lèi)對(duì)象?
54 多態(tài)的原理剖析
//示例:多態(tài)原理剖析
//動(dòng)物類(lèi) class Animal { public:virtual void speak(){cout << "動(dòng)物在說(shuō)話(huà)" << endl;} };//貓類(lèi) class Cat :public Animal { public://虛函數(shù)void speak(){cout << "小貓?jiān)谡f(shuō)話(huà)" << endl;} };//狗類(lèi) class Dog :public Animal { public://虛函數(shù)void speak(){cout << "小狗在說(shuō)話(huà)" << endl;} }; void doSpeak(Animal &animal) {animal.speak(); }void test01() {Cat cat;doSpeak(cat);Dog dog;doSpeak(dog);}多態(tài)優(yōu)點(diǎn):代碼組織結(jié)構(gòu)清晰,可讀性強(qiáng),利于前期和后期的擴(kuò)展及維護(hù)
在真實(shí)的開(kāi)發(fā)中,提倡 開(kāi)閉原則
開(kāi)閉原則:對(duì)擴(kuò)展進(jìn)行開(kāi)發(fā),對(duì)修改進(jìn)行關(guān)閉
56 純虛函數(shù)和抽象函數(shù)
當(dāng)類(lèi)中有了純虛函數(shù),這個(gè)類(lèi)就是抽象類(lèi)?
?//抽象類(lèi)無(wú)法實(shí)例化對(duì)象
?//子類(lèi)必須重寫(xiě)抽象類(lèi)中的純虛函數(shù),否則也屬于抽象類(lèi),無(wú)法實(shí)例化對(duì)象
58 虛析構(gòu)和純虛析構(gòu)
父類(lèi)指針在析構(gòu)的時(shí)候,不會(huì)調(diào)用子類(lèi)中析構(gòu)函數(shù),導(dǎo)致子類(lèi)中如果有堆區(qū)屬性,出現(xiàn)內(nèi)存泄漏?
虛析構(gòu)和純虛析構(gòu)的共性:
- 可以解決父類(lèi)指針釋放子類(lèi)對(duì)象時(shí)不干凈的問(wèn)題
- 都需要有具體的函數(shù)實(shí)現(xiàn)
虛析構(gòu)和純虛析構(gòu)的區(qū)別:
- 如果是純虛析構(gòu),該類(lèi)屬于抽象類(lèi),無(wú)法實(shí)例化對(duì)象
虛析構(gòu):virtual ~類(lèi)名(){}
純虛析構(gòu):virtual ~類(lèi)名() = 0;//聲明
? ? ? ? ? ? ? ? ? 類(lèi)名 :: ~類(lèi)名() {}? //具體實(shí)現(xiàn)
總結(jié):
5 文件操作
文本文件
143 寫(xiě)文件
寫(xiě)文件步驟:
144 讀文件
ifstream ifs; ifs.open("text.txt", ios::in); if (!ifs.is_open()) {cout << "文件打開(kāi)失敗" << endl;return; } //讀文件的四種方式 //1 char buf[1024] = { 0 }; while (ifs >> buf) {cout << buf << endl; }//2 char buf[1024] = { 0 }; while (ifs.getline(buf, sizeof(buf))) {cout << buf << endl; }//3 string buf; while (getline(ifs, buf)) {cout << buf << endl; }*//4不推薦 char c; while ((c = ifs.get()) != EOF) {cout << c; }二進(jìn)制文件
以二進(jìn)制的方式對(duì)文件進(jìn)行讀寫(xiě)操作
打開(kāi)方式要指定為ios::binary
145 寫(xiě)文件
ofstream ofs; ofs.open("Person.txt", ios::out | ios::binary); Person p = { "張三",18 }; ofs.write((const char *)&p,sizeof(Person)); ofs.close();146 讀文件
ifstream ifs;ifs.open("person.txt", ios::in | ios::binary);if (!ifs.is_open()){cout << "文件打開(kāi)失敗" << endl;return;}Person p;ifs.read((char*)&p, sizeof(Person));cout << p.m_name << p.m_age << endl;ifs.close();總結(jié)
以上是生活随笔為你收集整理的笔记 黑马程序员C++教程从0到1入门编程——核心编程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 嘉立创又搞大事情了,与你我相关!
- 下一篇: s3c2440移植MQTT