日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

笔记 黑马程序员C++教程从0到1入门编程——核心编程

發布時間:2023/12/20 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 笔记 黑马程序员C++教程从0到1入门编程——核心编程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

1 內存分區模型

程序運行前

01 代碼區

02 全局區

程序運行后

03 棧區

04 堆區

05 new操作符

2 引用

06 引用的基本使用

07 引用注意事項

08 引用做函數參數

09 引用做函數返回值

10 引用的本質

11 常量引用

3 函數提高

12函數默認參數

13 函數占位參數

14 函數重載

4 類和對象

封裝

16 封裝的意義 屬性和行為作為整體

對象特性:對象的初始化和清理

23 構造函數和析構函數

24 構造函數的分類和調用

?25 拷貝構造函數調用時機

26 構造函數調用規則

27 深拷貝和淺拷貝

28 初始化列表

29 類對象作為類成員

30 靜態成員

對象特性:C++對象模型和this指針

32 成員變量和成員函數分開存儲

33 this指針

34 空指針訪問成員函數

35 const修飾成員函數

友元

36 全局函數做友元

37 友元類

38 成員函數做友元

C++運算符重載

39 加號運算符重載?

40 左移運算符重載

41 遞增運算符重載

42 賦值運算符重載

43 關系運算符重載

44 函數調用運算符重載

繼承

45 基本語法

46 繼承方式

47 繼承中的對象模型

48 構造和析構順序

49 同名成員處理

50 同名靜態成員處理

51 多繼承語法

52 菱形繼承問題以及解決方法

多態

53 多態的基本語法

54 多態的原理剖析

56 純虛函數和抽象函數

58 虛析構和純虛析構

5 文件操作

文本文件

143 寫文件

144 讀文件

二進制文件

145 寫文件

146 讀文件


1 內存分區模型

程序運行前

程序運行運行前,編譯后:

01 代碼區

代碼區:存放函數的二進制代碼,有操作系統進行管理
共享,只讀?

02 全局區

全局區:存放全局變量靜態變量(static),常量(字符串常量const修飾的全局常量(全局常量))
【在程序結束后由操作系統釋放】
//不在全局區的數據:局部變量、const修飾的局部變量(局部常量)?

程序運行后

03 棧區

棧區:由編譯器自動分配釋放,存放函數的形參,局部變量
//不要返回局部變量的地址,棧區開辟的數據由編譯器自動釋放

04 堆區

堆區:由程序員分配和釋放,若程序員不釋放,系統結束時由操作系統回收
//new可以創建堆區數據,返回的是創建的堆區的地址,要用指針接收

05 new操作符

? int* arr = new int[10];//堆區開辟數組

delete[] arr;//釋放數組

2 引用

06 引用的基本使用

作用:給變量起別名
語法:數據類型 &別名=原名;

07 引用注意事項

引用必須初始化
引用初始化后不可以改變

int a = 10;//int& b;//err,引用必須初始化int& b = a;int c = 20;b = c;//這是賦值操作,不是更改引用,把b的值賦值成c的值20cout << a << b << c << endl;//20 20 20

08 引用做函數參數

引用傳遞讓形參修飾實參,簡化指針修改實參?

通過引用參數產生的效果同按地址傳遞是一樣的,引用的語法更清楚簡單

//引用傳遞 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 引用做函數返回值

作用:引用是可以作為函數的返回值存在的

注意:不要返回局部變量引用

用法:函數返回值是引用時,函數調用可以作為左值

//返回局部變量引用,非法操作 int& test01() {int a = 10;//局部變量存放在棧區return a; }//返回靜態變量引用,可以執行 int& test02() {static int a = 10;//靜態變量,存放在全局區,系統釋放return a; }int main() {//1.不要返回局部變量的引用int& ref = test01();cout << ref << endl;//第一次正確,因為編譯器做了保留//cout << ref << endl;//第二次錯誤,因為a的內存已經釋放int& ref2 = test02();cout << ref2 << endl;//10cout << ref2 << endl;//10cout << ref2 << endl;//10//2.如果函數的返回值是引用,這個函數的調用可以作為左值進行賦值操作test02() = 1000;cout << ref2 << endl;//1000cout << ref2 << endl;//1000system("pause");return 0; }

10 引用的本質

引用的本質在C++內部實現是一個指針常量

指針的指向是不可以修改指針指向的值是可以改動

11 常量引用

用來修飾形參,防止誤操作

(在函數形參列表中,可以加const修飾形參,防止形參改變實參)

void showValue(const int& val)//函數中利用常量引用防止誤操作修改實參 {cout << val; } int main() {//常量引用:用來修飾形參,防止誤操作int a = 10;//int& ref = 10;//err,引用必須引一塊合法的內存空間const int& ref = 10;//編譯器幫修改為int temp=10;int &ref=temp;//ref = 20;//加入const之后,變為只讀,不可修改int a = 100;showValue(a);system("pause");return 0; }

3 函數提高

12函數默認參數

語法:返回值類型 函數名(形參=默認值){ }

  • C++中函數的形參列表中的形參是可以有默認值的
  • 如果有傳入數據,就用傳入的數據,如果沒有就用默認值
  • 如果某個位置已經有了默認參數,那么這個位置之后,從左到右都必須有默認值
  • 聲明和實現只能有一個有默認參數;如果函數聲明有默認參數,函數實現就不能有默認參數

13 函數占位參數

C++中函數形參列表里可以有占位參數,用來占位,調用函數時必須填補該位置

語法:返回值類型 函數名(數據類型){}
?? ?//占位參數還可以有默認參數 (int=10),有默認值時,調用時可以不用傳值

14 函數重載

函數名可以相同,提高復用性

滿足條件:

  • 同一個作用域;
  • 函數名稱相同;
  • 函數參數類型不同或者個數不同或者順序不同
  • 函數的返回值不可以作為函數重載的條件

    注意事項:

  • 引用可以作為函數重載條件,const int &a和int &a(const可以作為引用重載條件)
  • 函數重載碰到默認參數,容易出現二義性,盡量避免
  • 4 類和對象

    面向對象三大特性:封裝、繼承、多態
    萬物是對象,有屬性和行為

    具有相同性質的對象,可以抽象為類

    封裝

    16 封裝的意義 屬性和行為作為整體

    //設計一個圓類,求周長

    const double PI = 3.14;class Circle {//訪問權限:公共權限 public ://屬性int m_r;//半徑//行為:獲取圓的周長double calculateZC(){return 2 * PI * m_r;} };//實例化(通過一個類,創建一個對象的過程)Circle c1;//通過圓類,創建具體的圓(對象)c1.m_r = 10;//給圓的對象的屬性賦值cout << "圓的周長為:" << c1.calculateZC() << endl;

    實例化:通過一個類,創建一個對象的過程

    類中的屬性和行為,統稱為成員

    • 屬性 ?成員屬性 成員變量
    • 行為 成員函數 成員方法

    類在設計時,可以把屬性和行為放在不同的權限下,加以控制

    18?三種訪問權限
    //公共權限 public? ? ? ? ? 成員類內可以訪問,類外可以訪問
    //保護權限 protected? ? 類內可以訪問,類外不可以訪問? ? ? ? ? ? 兒子可以訪問父親中的保護內容
    //私有權限 private? ? ? ? 類內可以訪問,類外不可以訪問? ? ? ? ? ? 兒子不可以訪問父親中的私有內容

    19 struct和class的區別:

    默認的訪問權限不同?
    struct默認權限是? 公共? public
    class默認權限是? ?私有? private

    20 成員屬性設置為私有的優點

  • 可以自己控制讀寫權限
  • 對于寫權限,可以檢測數據的有效性
  • //設計立方體類

    //創建立方體類 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;}//利用局部函數判斷是否相等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; };//利用全局函數判斷兩個立方體是否相等 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;//利用全局函數判斷bool ret=isSame(c1,c2);if (ret)cout << "相等" << endl;elsecout << "不相等" <<endl;//利用局部函數判斷bool ret1 = c1.isSamebyclass(c2);if (ret1)cout << "相等" << endl;elsecout << "不相等" << endl;system("pause");return 0; }

    //判斷點和圓的關系?

    在類中可以讓另一個類 作為本類中的成員

    可以把一個類拆在不同文件中 .h聲明 .cpp實現

    對象特性:對象的初始化和清理

    每個對象也會有初識設置以及對象銷毀前的清理數據的設置

    23 構造函數和析構函數

    編譯器自動調用,完成對象初始化和清理工作

    • 構造函數:創建對象時對象的成員屬性賦值
    • 析構函數:對象銷毀前,清理工作

    構造函數:類名(){}

  • 沒有返回值,不用寫void
  • 函數名與類名相同
  • 構造函數可以有參數,可以發生重載
  • 創建對象的時候,構造函數會自動調用,而且只調用一次
  • 析構函數:~類名(){}

  • 沒有返回值,不用寫void
  • 函數名與類名相同
  • 構造函數不可以有參數,不可以發生重載
  • 創建對象的時候,構造函數會自動調用,而且只調用一次?
  • 24 構造函數的分類和調用

    構造函數分類:
    按照參數:有參構造和無參構造(默認構造)
    按照類型:普通構造和拷貝構造

    調用方式:
    1.括號法2.顯示法3.隱式轉換法

    class Person { public://無參構造Person(){cout << "Person的無參(默認)構造函數調用" << endl;}//有參構造Person(int a){age = a;cout << "Person的有參構造函數調用" << endl;}//拷貝構造函數Person(const Person &p)//const+引用方式傳入{//將傳入的人身上的所有屬性,拷貝到當前對象身上age = p.age;cout << "Person的拷貝構造函數調用" << endl;}~Person(){cout << "Person的析構函數調用" << endl;}int age; };void test01() {//1.括號法Person p;//默認構造函數的調用,調用默認構造函數的時候,不要加()Person p1(10);Person p2(p1);//拷貝構造函數調用cout << "p2的年齡為" << p1.age << endl;cout << "p2的年齡為" << p2.age << endl;//注意:調用默認構造函數的時候,不要加()//Person p1();//err//編譯器會認為是一個函數的聲明,不會認為在創建對象2.顯示法Person p1;Person p2 = Person(10);Person p3 = Person(p2);//Person(10);//匿名對象,特點:當前行執行結束后,系統會立即回收掉匿名對象注意:不要利用拷貝構造函數 初始化匿名對象Person(p3);編譯器會認為在對象聲明==Person p3;3.隱式轉換法Person p4 = 10;//相當于 Person p4=Person(10);Person p5 = p4; }int main() {test01();system("pause");return 0; }

    ?25 拷貝構造函數調用時機

    拷貝構造函數調用時機三種情況:

  • 使用一個已經創建完畢的對象來初始化一個對象
  • 值傳遞的方式給函數參數傳值
  • 以值方式返回局部對象
  • class Person { public:Person(){cout << "默認構造函數的調用" << endl;}Person(int age){m_Age = age;cout << "有參構造函數的調用" << endl;}Person(const Person &p){m_Age = p.m_Age;cout << "拷貝構造函數的調用" << endl;}~Person(){cout << "析構函數的調用" << endl;}int m_Age; };//1.使用一個已經創建完畢的對象來初始化一個對象void test01() {Person p1(20);Person p2(p1);cout << "p2的年齡為:" << p2.m_Age << endl; }//2.值傳遞的方式給函數參數傳值void doWork(Person p) {} void test02() {Person p;doWork(p); } //3.以值方式返回局部對象Person doWork2() {Person p1;return p1; } void test03() {Person p = doWork2(); } int main() {//test01();//test02();test03();system("pause");return 0; }

    26 構造函數調用規則

    調用規則:

    如果我們寫了有參構造函數,編譯器就不再提供默認構造,依然提供拷貝構造
    如果我們寫了拷貝構造函數,編譯器就不再提供其他普通構造函數?

    27 深拷貝和淺拷貝

    淺拷貝:簡單的復制拷貝操作
    淺拷貝帶來的問題就是堆區的內存重復釋放

    深拷貝:在堆區重新申請空間,進行拷貝操作

    //如果屬性有在堆區開辟的,一定要自己提供拷貝構造函數,防止淺拷貝帶來的問題

    class Person { public:Person(){cout << "Person的默認構造函數調用" << endl;}Person(int age,int height){m_Age = age;m_Height=new int(height);cout << "Person的有參構造函數調用" << endl;}//自己實現拷貝構造函數,解決淺拷貝帶來的問題Person(const Person& p){cout << "Person拷貝構造函數調用" << endl;m_Age = p.m_Age;//m_Height = p.m_Height;編譯器默認實現的代碼,淺拷貝//深拷貝操作m_Height = new int(*p.m_Height);}~Person(){//析構代碼,將堆區開辟數據做釋放操作if (m_Height != NULL){delete m_Height;m_Height = NULL;}cout << "Person的析構函數調用" << endl;}int m_Age;//年齡int* m_Height; };void test01() {Person p1(18,160);cout << "p1的年齡為:" << p1.m_Age <<"身高為:"<<*p1.m_Height<< endl;Person p2(p1);cout << "p2的年齡為:" << p2.m_Age << "身高為:" << *p2.m_Height << endl;} int main() {test01();system("pause");return 0; }

    28 初始化列表

    //初始化列表Person(int a,int b,int c) :m_A(a), m_B(b), m_C(c){} //屬性賦初值 Person p(31,20,10);

    29 類對象作為類成員

    類中的成員可以是另一個類的對象,我們稱該成員為對象成員

    • 當其他類對象作為本類成員,構造時候先構造類對象,再構造自身
    • 當其他類對象作為本類成員,析構時候先析構自身,再析構類對象

    構造順序與析構順序相反

    class Phone { public:Phone(string pName){m_PName = pName;cout << "phone的構造函數調用" << endl;}~Phone(){cout << "phone的析構函數調用" << endl;}string m_PName; }; class Person { public:Person(string name, string pName):m_Name(name),m_phone(pName){cout << "person的構造函數調用" << endl;}~Person(){cout << "person的析構函數調用" << endl;}string m_Name;Phone m_phone; };

    30 靜態成員

    靜態成員變量:

    • 所有對象共享同一份數據
    • 在編譯階段分配內存(程序運行前-全局區)
    • 類內聲明,類外初始化
    class Person { public:static int m_A;//類內聲明};int Person::m_A = 100;//類外初始化void test01() {Person p;cout << p.m_A << endl;//100Person p2;p2.m_A = 200;//所有對象共享同一份數據cout << p.m_A << endl;//200 }

    靜態成員變量,不屬于某個對象上,所有對象都共享同一份數據?
    有兩種訪問方式:

  • 通過對象進行訪問
  • 通過類名進行訪問
  • Person p; cout<<p.m_A<<endl;cout<<Person::m_A<<endl;

    靜態成員變量有訪問權限,類外訪問不到私有靜態成員變量

    31 靜態成員函數

    • 所有對象共享同一個函數
    • 靜態成員函數只能訪問靜態成員變量

    //兩種訪問方式:通過對象,通過類名
    //靜態成員函數也是有訪問權限的,類外訪問不到私有的靜態成員函數

    class Person { public://靜態成員函數static void func(){m_A = 100;//靜態成員函數可以訪問靜態成員變量,共享的//m_B = 200;//靜態成員函數不可以訪問非靜態成員變量,因為無法區分到底是哪個對象的m_Bcout << "ststic void func()的調用" << endl;}static int m_A;//類內聲明,類外初始化int m_B;//非靜態成員變量 };int Person::m_A=0;//類外初始化void test01() {//靜態成員函數有兩種訪問方式//通過對象訪問Person p;p.func();//通過類名訪問,因為不屬于某一個對象上,不創建對象也可以訪問Person::func(); }

    對象特性:C++對象模型和this指針

    32 成員變量和成員函數分開存儲

    只有非靜態成員變量 屬于對象上的數據

    ??空對象占用內存空間為:1
    ?? ?//C++編譯器會給每個空對象也分配一個字節空間,是為了區分空對象占內存的位置
    ?? ?//每個空對象也應該有一個獨一無二的內存地址

    class Person {int m_A;//非靜態成員變量 屬于對象上的數據static int m_B;//靜態成員變量 不屬于類的對象上void func(){}//非靜態成員函數 不屬于類的對象上static void func2() {}//靜態成員函數 不屬于類的對象上 }; int Person::m_B=0;void test02() {Person p;cout << "sizeofp=" << sizeof(p) << endl;//4 }

    33 this指針

    this指針:指向被調用的成員函數所屬的對象
    this指針是隱含每一個非靜態成員函數內的一種指針
    this指針不需要定義,直接使用
    用途:
    //當形參和成員變量同名時,可用this指針來區分
    //在類的非靜態成員函數中返回對象本身,可使用return *this

    class Person { public:Person(int age){//this指針指向被調用的成員函數所屬的對象this->age = age;}//如果用Person返回就是用值的方式返回,會用到拷貝構造函數,Person返回的和自身是不一樣的數據//用引用方式返回,不會創建新的對象,會一直返回P2本體Person& PersonAddAge(Person& p)//Person& 不返回引用就會通過拷貝構造創建新對象,就不是原來的對象了{this->age += p.age;//this是指向p2的指針,*this指向的就是p2這個對象的本體return *this;}int age; }; void test02() {Person p1(10);Person p2(10);p2.PersonAddAge(p1).PersonAddAge(p1).PersonAddAge(p1);//鏈式編程思想cout << "p2的年齡為:" << p2.age << endl; } void test01() {Person p1(18);cout << "p1的年齡為:" << p1.age << endl; }test01();test02();

    34 空指針訪問成員函數

    C++中允許空指針調用成員函數,也要注意有沒有用到this指針
    //如果用到this指針,需要判斷保證代碼的健壯性

    35 const修飾成員函數

    常函數
    成員函數后加const稱為常函數
    //常函數內不可以修改成員屬性(指針指向的值不能修改)
    //成員屬性聲明時加關鍵字mutable后,在常函數中依然可以修改
    常對象
    聲明對象前加const稱為常對象
    //常對象只能調用常函數

    友元

    36 全局函數做友元

    class Building {friend void goodgay(Building* builiding);//goodgay是Building好朋友,可以訪問Builing中私有成員 public:Building(){m_SittingRoom = "客廳";m_BedRoom = "臥室";} public:string m_SittingRoom;private:string m_BedRoom;}; //全局函數 void goodgay(Building *builiding) {cout << "全局函數正在訪問:" << builiding->m_BedRoom << endl;cout << "全局函數正在訪問:" << builiding->m_SittingRoom << endl; }

    37 友元類

    friend class goodgay;//goodgay類是本類的好朋友,可以訪問本類中私有的成員

    38 成員函數做友元

    friend void Goodgay::visit01();//goodgay類下的visit成員函數作為本類的好朋友,可以訪問私有成員

    C++運算符重載

    運算符重載:對已有運算符重新進行定義,賦予另一種功能,以適應不同的數據類型

    39 加號運算符重載?

    作用:實現兩個自定義數據類型相加的運算
    //對于內置的數據類型表達式運算符是不可能改變的
    //不要濫用運算符重載

    class Person { public://1.成員函數重載加號: Person p3=p1+p2;成員函數的本質是 Person p3=p1.operator+(p2);/*Person operator+(Person& p){Person temp;temp.m_A = this->m_A + p.m_A;temp.m_B = this->m_B + p.m_B;return temp;}*/int m_A;int m_B;};//2.全局函數重載加號: Person p3=p1+p2;全局函數的本質是 Person p3= operator+(p1,p2); Person operator+(Person &p1,Person &p2) {Person temp;temp.m_A = p1.m_A + p2.m_A;temp.m_B = p1.m_B + p2.m_B;return temp; }//3.運算符重載也可以發生函數重載 Person operator+(Person& p1, int num) {Person temp;temp.m_A = p1.m_A +num;temp.m_B = p1.m_B +num;return temp; } void test01() {Person p1;p1.m_A = 10;p1.m_B = 10;Person p2;p2.m_A = 10;p2.m_B = 10;Person p3 = p1 + p2;//運算符重載也可以發生函數重載Person p4 = p1 + 100;cout << "p3.m_A=" << p3.m_A << endl;cout << "p3.m_B=" << p3.m_B << endl;cout << "p4.m_A=" << p4.m_A << endl;cout << "p4.m_B=" << p4.m_B << endl; }

    40 左移運算符重載

    輸出左移運算符配合友元可以實現輸出自定義數據類型

    class Person {friend ostream& operator<<(ostream& cout, Person& p); public:Person(int a, int b){m_A = a;m_B = b;} private://不會利用成員函數重載左移運算符<<,因為無法實現cout在左側int m_A;int m_B;};//只能利用全局函數重載左移運算符 ostream& operator<<(ostream &cout,Person &p)//本質是operator<<(cout,p) 簡化cout<<p {cout << "m_A=" << p.m_A << endl;cout << "m_B=" << p.m_B << endl;return cout;//為了可以無限往后追加輸出 } void test01() {Person p(10, 10);cout << p <<"hello"<< endl;; }

    41 遞增運算符重載

    通過重載遞增運算符,實現自己的整形數據

    前置遞增返回參數,后置遞增返回值??

    //++//自定義整形 class MyInteger {friend ostream& operator<<(ostream& cout, MyInteger myint); public:MyInteger(){m_Num = 0;}//重載++運算符//1.重載前置++ MyInteger& operator++()//返回引用是為了一直對一個數據進行遞增操作{//先進行++運算m_Num++;//再將自身返回return *this;}//2.重載后置++ //返回的是值,因為返回的是局部變量MyInteger operator++(int)//int代表占位參數,可以用于區分前置和后置遞增,編譯器會認為這是后置遞增重載{//先記錄當時結果MyInteger temp = *this;//后遞增m_Num++;//再返回之前記錄的結果return temp;} private:int m_Num; };//重載左移運算符 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 賦值運算符重載

    Person& operator=(Person& p){//編譯器提供的是淺拷貝//m_Age=p.m_Age;//應該先判斷有屬性在堆區,如果有先釋放干凈,然后再深拷貝if (m_Age != NULL){delete m_Age;m_Age = NULL;}m_Age=new int(*p.m_Age);//深拷貝return *this;}

    43 關系運算符重載

    //重載==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 函數調用運算符重載

    函數調用運算符()也可以重載

    由于重載后使用的方式非常像函數的調用,因此稱為仿函數

    仿函數沒有固定的寫法,非常靈活

    //打印輸出 class MyPrint { public://重載函數調用運算符void operator()(string test){cout << test << endl;} }; void test01() {MyPrint myPrint;myPrint("hello");//由于使用起來類似于函數調用,稱為仿函數 } //仿函數非常靈活,沒有固定的寫法 //加法類 class MyAdd { public:int operator()(int num1, int num2){return num1 + num2;} }; void test02() {MyAdd myadd;int ret = myadd(100, 200);cout << ret << endl;//匿名函數對象 //MyAdd()cout << MyAdd()(100, 200) << endl; } int main() {test01();test02();return 0; }

    繼承

    45 基本語法

    繼承的好處:減少重復代碼
    語法: class 子類:繼承方式 父類

    ? ? ? ? ? ? class A : publib B
    ????????????A類,子類也稱為派生類
    ????????????B類,父類也稱為基類

    派生類中的成員,包含兩大部分:一類是從基類繼承過來的,一類是自己增加的成員

    從基類繼承過來的表現其共性,而新增的成員體現其個性

    46 繼承方式

    ?繼承的三種方式:

    • 公共繼承
    • 保護繼承
    • 私有繼承

    47 繼承中的對象模型

    class Base { public:int a; protected:int b; private:int c;};class Son :public Base { public:int d;};void test01() {//父類中所有靜態成員屬性都會被子類繼承下去//父類中私有成員屬性是被編譯器給隱藏了,因此是訪問不到,但是確實被繼承下去了cout << "size of Son=" << sizeof(Son) << endl;//16 }

    利用開發人員命令提示工具(Developer Command Prompt for VS 2019)查看對象模型
    //跳轉盤符 F:
    //跳轉文件路徑 cd 具體路徑下
    //查看命令 cl /d1 reportSingleClassLayout類名 文件名
    ? ? ? ? ? ? ? ? F:\C++-code\0421繼承>cl /d1 reportSingleClassLayoutSon "129對象基本模型.cpp"?

    48 構造和析構順序

    子類繼承父類后,當創建子類對象,也會調用父類的構造函數
    繼承中的構造和析構的順序:
    先構造父類,再構造子類;析構順序與構造順序相反

    49 同名成員處理

    當子類與父類出現同名的成員,如何通過子類對象,訪問到其中的同名數據:
    1.訪問子類同名成員,直接訪問即可
    2.訪問父類同名成員,需要加作用域

    Son s;cout << "Son的m_A=" << s.m_A << endl;cout << "Base的m_A=" << s.Base::m_A << endl;//如果通過子類對象,訪問到父類中的同名成員,需要加作用域s.func();//直接調用的是子類中的同名函數s.Base::func();//調用的是父類的
    • 如果子類中出現和父類中同名的成員函數,子類的同名成員會隱藏掉父類中所有同名成員函數(包括重載版本)
    • 如果想訪問到父類中被隱藏的同名成員函數,需要加作用域?

    50 同名靜態成員處理

    ?同名靜態成員處理方式和非靜態處理方式一樣,只不過有兩種訪問方式(通過對象和通過類名

    class Base{public:static int m_A;static void func(){cout << "Base 的func的調用" << endl;}};int Base::m_A = 100;class Son :public Base{public:static int m_A;static void func(){cout << "Son 的func的調用" << endl;}};int Son::m_A = 200;void test01(){//通過對象訪問Son s;cout << "Son的m_A=" << s.m_A << endl;cout << "Base的m_A=" << s.Base::m_A << endl;//通過類名訪問cout << Son::m_A << endl;cout << Base::m_A << endl;cout << Son::Base::m_A << endl;//第一個::代表通過類名方式訪問,第二個::代表訪問父類作用域下的m_A}void test02(){//通過對象訪問Son s;s.func();s.Base::func();//通過類名訪問Son::func();Son::Base::func();}

    51 多繼承語法

    C++允許一個類繼承多個類

    語法:class 子類:繼承方式 父類1,繼承方式 父類2
    //多繼承可能會引發父類中有同名成員出現,需要加作用域
    //開發中不建議用多繼承

    //子類繼承兩個父類class Son :public Base1, public Base2 //父類中出現同名成員時,需要加作用域區分cout << s.Base1::m_A << endl;cout << s.Base2::m_A << endl;

    52 菱形繼承問題以及解決方法

    菱形繼承、鉆石繼承

    • 兩個派生類繼承同一個類
    • 又有某個類同時繼承兩個派生類?

    多態

    53 多態的基本語法

    動態多態滿足條件:

  • 要有繼承關系
  • 子類重寫父類的虛函數 ? //重寫:函數返回值類型 函數名 參數列表 完全相同
  • 動態多態使用:父類的指針或引用 指向子類對象?

    54 多態的原理剖析

    //示例:多態原理剖析

    //動物類 class Animal { public:virtual void speak(){cout << "動物在說話" << endl;} };//貓類 class Cat :public Animal { public://虛函數void speak(){cout << "小貓在說話" << endl;} };//狗類 class Dog :public Animal { public://虛函數void speak(){cout << "小狗在說話" << endl;} }; void doSpeak(Animal &animal) {animal.speak(); }void test01() {Cat cat;doSpeak(cat);Dog dog;doSpeak(dog);}

    多態優點:代碼組織結構清晰可讀性強,利于前期和后期的擴展及維護

    在真實的開發中,提倡 開閉原則
    開閉原則:對擴展進行開發,對修改進行關閉

    56 純虛函數和抽象函數

    當類中有了純虛函數,這個類就是抽象類?

    ?//抽象類無法實例化對象
    ?//子類必須重寫抽象類中的純虛函數,否則也屬于抽象類,無法實例化對象

    58 虛析構和純虛析構

    父類指針在析構的時候,不會調用子類中析構函數,導致子類中如果有堆區屬性,出現內存泄漏?

    虛析構和純虛析構的共性

    • 可以解決父類指針釋放子類對象時不干凈的問題
    • 都需要有具體的函數實現

    虛析構和純虛析構的區別

    • 如果是純虛析構,該類屬于抽象類,無法實例化對象

    虛析構:virtual ~類名(){}

    純虛析構virtual ~類名() = 0;//聲明
    ? ? ? ? ? ? ? ? ? 類名 :: ~類名() {}? //具體實現

    總結:

  • 虛析構和純虛析構就是用來解決通過父類指針釋放子類對象
  • 如果子類中沒有堆區數據,可以不寫虛析構或純虛析構
  • 擁有純虛析構函數的類也屬于抽象類
  • 5 文件操作

    文本文件

    143 寫文件

    寫文件步驟:

  • 包含頭文件#include<fstream>
  • 創建流對象 ofstream ofs;
  • 打開文件 ofs.open("文件路徑",打開方式);
  • 寫數據 ofs << "寫入的數據";
  • 關閉文件 ofs.close();
  • ofstream ofs; ofs.open("text.txt", ios::out); ofs << "姓名:張三" << endl; ofs.close();

    144 讀文件

    ifstream ifs; ifs.open("text.txt", ios::in); if (!ifs.is_open()) {cout << "文件打開失敗" << 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; }

    二進制文件

    以二進制的方式對文件進行讀寫操作

    打開方式要指定為ios::binary

    145 寫文件

    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 << "文件打開失敗" << endl;return;}Person p;ifs.read((char*)&p, sizeof(Person));cout << p.m_name << p.m_age << endl;ifs.close();

    總結

    以上是生活随笔為你收集整理的笔记 黑马程序员C++教程从0到1入门编程——核心编程的全部內容,希望文章能夠幫你解決所遇到的問題。

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