網(wǎng)上課程網(wǎng)站建設(shè)方案百度競價官網(wǎng)
文章目錄
- 1、面向過程和面向?qū)ο蟪醪秸J識
- 2、類的引入
- 3、類的定義
- 4、類的訪問限定符
- 5、類的作用域
- 6、類的實例化
- 7、計算類對象的大小
- 8、this指針
- 9、 C語言和C++實現(xiàn)Stack的對比
1、面向過程和面向?qū)ο蟪醪秸J識
C語言
是面向過程的,關(guān)注的是過程,分析出求解問題的步驟,通過函數(shù)調(diào)用逐步解決問題。
舉例子來理解一下就是,送外賣,先是商家做飯,打包,聯(lián)系外賣員,外賣員取貨,送貨,聯(lián)系買家,爬樓梯,敲門等。注重的是過程。
C++
是基于面向?qū)ο蟮?#xff0c;關(guān)注的是對象,將一件事情拆分成不同的對象,靠對象之間的交互完成。
舉例子來理解一下就是,商家,外賣員,買家。注重對象。
2、類的引入
C語言結(jié)構(gòu)體中只能定義變量,在C++中,結(jié)構(gòu)體內(nèi)不僅可以定義變量,也可以定義函數(shù)。比如:用C語言方式實現(xiàn)的棧,結(jié)構(gòu)體中只能定義變量;現(xiàn)在以C++方式實現(xiàn),會發(fā)現(xiàn)struct中也可以定義函數(shù)。
#nclude<stdlib.h>
#include<iostream>
using namespace std;typedef int DataType;
struct Stack
{void Init(size_t capacity){_array = (DataType*)malloc(sizeof(DataType) * capacity);if (nullptr == _array){perror("malloc申請空間失敗");return;}_capacity = capacity;_size = 0;}void Push(const DataType& data){// 擴容_array[_size] = data;++_size;}DataType Top(){return _array[_size - 1];}void Destroy(){if (_array){free(_array);_array = nullptr;_capacity = 0;_size = 0;}}DataType* _array;size_t _capacity;size_t _size;
};
int main()
{Stack s;s.Init(10);s.Push(1);s.Push(2);s.Push(3);cout << s.Top() << endl;s.Destroy();return 0;
}
在上面的結(jié)構(gòu)體定義,在
C++
當(dāng)眾更加的喜歡使用class
C++
中有struct
和class
創(chuàng)建結(jié)構(gòu)體(創(chuàng)建對象)兩種方法,從下面的代碼當(dāng)中可以了解到在結(jié)構(gòu)體當(dāng)中在次調(diào)用struct
必須要帶上struct
而class
就不需要。
struct List1
{struct List1* arr;
};class List2
{List2* ret;
};
3、類的定義
class className
{
// 類體:由成員函數(shù)和成員變量組成
};
class為定義類的關(guān)鍵字,ClassName為類的名字,{}中為類的主體,注意類定義結(jié)束時后面分號不能省略。
類體中內(nèi)容稱為類的成員:類中的變量稱為類的屬性或成員變量; 類中的函數(shù)稱為類的方法或者成員函數(shù)。
類的兩種定義方式:
- 聲明和定義全部放在類體中,需注意:成員函數(shù)如果在類中定義,編譯器可能會將其當(dāng)成內(nèi)聯(lián)函數(shù)處理。
- 類聲明放在.h文件中,成員函數(shù)定義放在.cpp文件中,注意:成員函數(shù)名前需要加類名::
一般情況下,更期望采用第二種方式。
下面簡單介紹一下成員變量(類的屬性)的命名問題。
就是在聲明成員變量的時候在變量名前加_
,防止在定義和賦值時的出現(xiàn)問題。當(dāng)然在這里使用其他的方法也是行的。
class Date
{
public:void Init(int year, int month, int day){year = year;//err}
private:int year;int month;int day;
};
class Date
{
public:void Init(int year, int month, int day){_year = year;//ture_month = month;_day = day;}
private:int _year;int _month;int _day;
};
4、類的訪問限定符
【訪問限定符說明】
- public修飾的成員在類外可以直接被訪問
- protected和private修飾的成員在類外不能直接被訪問(此處protected和private是類似的)
- 訪問權(quán)限作用域從該訪問限定符出現(xiàn)的位置開始直到下一個訪問限定符出現(xiàn)時為止
- 如果后面沒有訪問限定符,作用域就到 } 即類結(jié)束。
class的默認訪問權(quán)限為private,struct為public(因為struct要兼容C)
注意:訪問限定符只在編譯時有用,當(dāng)數(shù)據(jù)映射到內(nèi)存后,沒有任何訪問限定符上的區(qū)別
5、類的作用域
類定義了一個新的作用域,類的所有成員都在類的作用域中。在類體外定義成員時,需要使用
::
作用域操作符指明成員屬于哪個類域。
class Date
{
public:void Init(int year, int month, int day);
private:int _year;int _month;int _day;
};
//要指定該函數(shù)是在哪個類當(dāng)中聲明的。
void Date::Init(int year, int month, int day)//注意
{_year = year;//ture_month = month;_day = day;
}
6、類的實例化
用類類型創(chuàng)建對象的過程,稱為類的實例化
- 類是對對象進行描述的,是一個模型一樣的東西,限定了類有哪些成員,定義出一個類并沒有分配實際的內(nèi)存空間來存儲它;
- 一個類可以實例化出多個對象,實例化出的對象 占用實際的物理空間,存儲類成員變量
class Date
{
public:void Init(int year, int month, int day);
private:int _year;int _month;int _day;
};
void Date::Init(int year, int month, int day)
{_year = year;//ture_month = month;_day = day;
}int main()
{Date a;a.Init(1,1,1);return 0;
}
Date類是沒有空間的,只有Date類實例化出的對象才有具體的時間。
3. 做個比方。類實例化出對象就像現(xiàn)實中使用建筑設(shè)計圖建造出房子,類就像是設(shè)計圖,只設(shè)計出需要什么東西,但是并沒有實體的建筑存在,同樣類也只是一個設(shè)計,實例化出的對象才能實際存儲數(shù)據(jù),占用物理空間。
只有在類的實例化時才會為類中的變量開空間,成員變量是在類當(dāng)中開辟空間的,而成員函數(shù)并不是在類中開辟空間,所以在類的實例化時只會只需要開辟成員變量的空間。
為什么成員變量在對象當(dāng)中,而成員函數(shù)卻不在對象當(dāng)中?
1、每個對象中的成員變量都是不一樣的,需要獨立儲存。
2、每個對象調(diào)用成員函數(shù)都是一樣的,放在共享公共空間(代碼段)
7、計算類對象的大小
class A1 {
public:void f1() {}
private:int _a;
};
// 類中僅有成員函數(shù)
class A2 {
public:void f2() {}
};
// 類中什么都沒有---空類
class A3
{};
A1:4
A2:1
A3:1
結(jié)論:一個類的大小,實際就是該類中”成員變量”之和,當(dāng)然要注意內(nèi)存對齊
注意空類的大小,空類比較特殊,占位,編譯器給了空類一個字節(jié)來唯一標(biāo)識這個類的對象。
8、this指針
Date類中有 Init 與 Print 兩個成員函數(shù),函數(shù)體中沒有關(guān)于不同對象的區(qū)分,那當(dāng)d1調(diào)用 Init 函
數(shù)時,該函數(shù)是如何知道應(yīng)該設(shè)置d1對象,而不是設(shè)置d2對象呢?
C++中通過引入this指針解決該問題,即:C++編譯器給每個“非靜態(tài)的成員函數(shù)“增加了一個隱藏
的指針參數(shù),讓該指針指向當(dāng)前對象(函數(shù)運行時調(diào)用該函數(shù)的對象),在函數(shù)體中所有“成員變量”
的操作,都是通過該指針去訪問。只不過所有的操作對用戶是透明的,即用戶不需要來傳遞,編
譯器自動完成。
下面代碼是系統(tǒng)將透明的代碼顯示出來的樣子,從下面的圖片中也可以看出this用于區(qū)分不同對象。
#include<iostream>
using namespace std;
class Date
{
public:void Init(Date* this, int year, int month, int day){this->_year = year;this->_month = month;this->_day = day;}
private:int _year;int _month;int _day;
};int main()
{Date d1, d2;d1.Init(&d1, 2022, 1, 11);return 0;
}
指針的特性
- this指針的類型:類類型* const,即成員函數(shù)中,不能給this指針賦值。
- 只能在“成員函數(shù)”的內(nèi)部使用
- this指針本質(zhì)上是“成員函數(shù)”的形參,當(dāng)對象調(diào)用成員函數(shù)時,將對象地址作為實參傳遞給
this形參。所以對象中不存儲this指針。- this指針是“成員函數(shù)”第一個隱含的指針形參,一般情況由編譯器通過ecx寄存器自動傳
遞,不需要用戶傳遞
在上文當(dāng)中提到了成員函數(shù)(類的方法)存放在代碼段當(dāng)中,但是不要和函數(shù)參數(shù)和臨時變量存放的方法混淆,他們是存放在棧區(qū)。
接下來我么們來考慮兩個問題
- this指針存在哪里?
因為在計算類對象大小的時候,只是計算了成員變量的大小,所以并沒有給this指針開辟空間。
this指針存放在棧區(qū)(vs當(dāng)中存放在ecx寄存器當(dāng)中)- this指針可以為空嗎?
從下面的代碼中也是可以看出看到空指針解引用就是錯誤的,而是要看調(diào)用的對象當(dāng)中是否有解引用的操作。
#include<iostream>
using namespace std;
class Date
{
public:void Init(int year, int month, int day){cout << this << endl;this->_year = year;this->_month = month;this->_day = day;}void func(){cout << this << endl;cout << "func()" << endl;}
private:int _year;int _month;int _day;
};int main()
{Date* p = nullptr;p->func(); //正常運行p->Init(2023,3,1); //程序崩潰(*p).func(); //正常運行return 0;
}
9、 C語言和C++實現(xiàn)Stack的對比
c語言
可以看到,在用C語言實現(xiàn)時,Stack相關(guān)操作函數(shù)有以下共性:
- 每個函數(shù)的第一個參數(shù)都是Stack*
- 函數(shù)中必須要對第一個參數(shù)檢測,因為該參數(shù)可能會為NULL
- 函數(shù)中都是通過Stack*參數(shù)操作棧的
- 調(diào)用時必須傳遞Stack結(jié)構(gòu)體變量的地址
結(jié)構(gòu)體中只能定義存放數(shù)據(jù)的結(jié)構(gòu),操作數(shù)據(jù)的方法不能放在結(jié)構(gòu)體中,即數(shù)據(jù)和操作數(shù)據(jù)
的方式是分離開的,而且實現(xiàn)上相當(dāng)復(fù)雜一點,涉及到大量指針操作,稍不注意可能就會出
錯。
c++
C++中通過類可以將數(shù)據(jù) 以及 操作數(shù)據(jù)的方法進行完美結(jié)合,通過訪問權(quán)限可以控制那些方法在
類外可以被調(diào)用,即封裝,在使用時就像使用自己的成員一樣,更符合人類對一件事物的認知。
而且每個方法不需要傳遞Stack*的參數(shù)了,編譯器編譯之后該參數(shù)會自動還原,即C++中 Stack *
參數(shù)是編譯器維護的,C語言中需用用戶自己維護。
最后:文章有什么不對的地方或者有什么更好的寫法歡迎大家在評論區(qū)指出 |