義烏多語言網(wǎng)站建設(shè)seo網(wǎng)絡(luò)推廣技術(shù)
目錄
面向?qū)ο蟮木幊?/p>
類的引入
簡介
類的定義
簡介
訪問限定符
命名規(guī)則
封裝
簡介
類的作用域
類的大小及存儲(chǔ)模型
this指針
簡介
面向?qū)ο蟮木幊?/h1>
C++與C語言不同,C++是面向?qū)ο蟮木幊?#xff0c;那么什么是面向?qū)ο蟮木幊棠?#xff1f;
C語言編程,規(guī)定了編程的每一步指令,程序從上而下一步一步按照指令,最終達(dá)到想要的結(jié)果,而面向?qū)ο笫橇硪环N思路,將一件事情拆分成不同的對(duì)象,任務(wù)需要依靠對(duì)象之間的交互完成,也就是說關(guān)注模塊和模塊之間的關(guān)系。
類的引入
簡介
類是C++中重要的概念,從C語言的結(jié)構(gòu)體升級(jí)而來,C語言的結(jié)構(gòu)體只能定義變量,C++中結(jié)構(gòu)體不僅可以定義變量還能定義函數(shù)(成員變量/成員屬性,成員函數(shù)/成員方法)
typedef int DataType;
struct Stack
{void Init(size_t capacity){_array = (DataType*)malloc(sizeof(DataType) * capacity);if (nullptr == _array){perror("malloc申請(qǐng)空間失敗");return;}_capacity = capacity;_size = 0;}void Push(const DataType& data){// 擴(kuò)容_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;}
類的定義
C++中用class作為關(guān)鍵字定義類,其結(jié)構(gòu)如下:
class classname
{//類體//成員變量(成員屬性)//成員函數(shù)(成員方法)
};
訪問限定符
C++中設(shè)置了訪問限定符,其作用是設(shè)置類體的屬性,訪問限定符作用域從當(dāng)前限定符開始直到下個(gè)訪問限定符出現(xiàn)結(jié)束,如果沒有訪問限定符則直到類結(jié)束;
1、public 修飾的類體,可以直接被外部訪問;
2、protected(保護(hù))與private(私有)修飾的類體有同樣的特征不允許被外部訪問;
3、struct與class在默認(rèn)的訪問限定符不同,struct為了兼容c語言,默認(rèn)的是public,class默認(rèn)的是private。
命名規(guī)則
先看一下下面代碼
class Date
{
private:int year;int month;int day;
public:void init(int year, int month, int day){year = year;month = month;day = day;}void print(){printf("%d-%d-%d\n", year, month, day);}
};
void init(int year, int month, int day){year = year;month = month;day = day;}
這段代碼閱讀起來很不方便,形參與類中的成員變量無法區(qū)別,為了更好的閱讀,在成員變量命名時(shí)可以加以區(qū)分;
class Date
{
private:int _year;int _month;int _day;
public:void init(int year, int month, int day){_year = year;_month = month;_day = day;}void print(){printf("%d-%d-%d\n", _year, _month, _day);}
};
封裝
簡介
C++中存在多種特性,面向?qū)ο蟮淖钪饕氖欠庋b,繼承,多態(tài);
類和對(duì)象的階段,主要是封裝的特性,那么什么是封裝呢?
簡單的說,封裝是一種管理行為,將程序的屬性與方法結(jié)合在一起,隱藏對(duì)象的屬性和細(xì)節(jié),僅保留對(duì)外接口和對(duì)象進(jìn)行交互,封裝的特性在C++的類中體現(xiàn)的很明顯;
class Date
{
private:int year;int month;int day;
public:void init(int year, int month, int day){year = year;month = month;day = day;}void print(){printf("%d-%d-%d\n", year, month, day);}
};int main()
{Date s;s.print();system("pause");return 0;
}
?上面的代碼中,成員變量無法通過外部進(jìn)行修改,只能通過init函數(shù)進(jìn)行修改;
類的大小及存儲(chǔ)模型
先看下面的代碼:
class Date
{
public:int _year;int _month;int _day;void init(int year, int month, int day){_year = year;_month = month;_day = day;}void print(){printf("%d-%d-%d\n", _year, _month, _day);}
};int main()
{Date s;printf("類的大小:%d\n", sizeof(s));system("pause");return 0;
}
上面這段代碼的結(jié)果為12。為什么是12而不是20(包含兩個(gè)函數(shù)的指針),這由類的存儲(chǔ)模型決定的。
類的存儲(chǔ)模型
?內(nèi)存通常分為棧區(qū),堆區(qū),靜態(tài)區(qū),常量區(qū)等,(棧區(qū)的空間非常小)為了節(jié)省空間,編譯器會(huì)將成員函數(shù)放在常量區(qū)(代碼段)中,使用時(shí)尋找函數(shù)。
this指針
先看下面的代碼及運(yùn)行結(jié)果
class Date
{
private:int _year;int _month;int _day;
public:Date(int year=1, int month=1, int day=1){_year = year;_month = month;_day = day;}void print(){printf("%d-%d-%d\n", _year, _month, _day);}
};int main()
{Date d1(2023,5,7);Date d2(2024, 6, 8);d1.print();d2.print();system("pause");return 0;
}
?成員函數(shù)存儲(chǔ)在常量區(qū),那為什么d1和d2調(diào)用時(shí)會(huì)打印出不同的結(jié)果呢?
這是因?yàn)轭愔械暮瘮?shù)有一個(gè)隱藏的參數(shù)this指針。
void thisprint(Date *this)//this指針隱藏在類的函數(shù)中,不能手寫,編譯器自動(dòng)完成
那么this指針又是什么呢?
class Date
{
private:int _year;int _month;int _day;
public:Date(int year=1, int month=1, int day=1){_year = year;_month = month;_day = day;}void print(){printf("%d-%d-%d\n", _year, _month, _day);}void thisprint(){printf("this指針:%p\n", this);}
};int main()
{Date d1(2023,5,7);Date d2(2024, 6, 8);printf("d1的地址: %p\n", &d1);d1.thisprint();printf("d2的地址: %p\n", &d2);d2.thisprint();system("pause");return 0;
}
?
?通過上面代碼的結(jié)果,this指針就是類的地址,那么可以由以下結(jié)論;
void print(){printf("%d-%d-%d\n", this->_year, this->_month, this->_day);}
//類能通過常量區(qū)的成員函數(shù)打印值,是通過指針調(diào)用完成的。
?為了保護(hù)this指針的值不被修改,this指針會(huì)用const修飾,寫成const int * this(指針指向的值無法被修改? ?int * const this指針指向的變量不能被修改);
?this指針也是存在棧區(qū)中,其作用域與生命周期隨著函數(shù)的調(diào)用而產(chǎn)生,隨著函數(shù)的銷毀而消失,VS下通常優(yōu)化在寄存器ecx中;
this 指針可以為空嗎?
//先看下這段代碼
class A
{
public:void Print(){std::cout << "Print()" << std::endl;}
private:int _a;
};
int main()
{A* p = nullptr;p->Print();system("pause");return 0;
}
//結(jié)構(gòu)體的指針為nullptr,this指針為nullptr,在調(diào)用函數(shù)時(shí)Print函數(shù)從常量區(qū)中調(diào)用,與this指針無關(guān),所以該程序可以正常運(yùn)行;
//再看下面這段代碼
class A
{
public:void PrintA(){std::cout << _a << std::endl;}
private:int _a;
};
int main()
{A* p = nullptr;p->PrintA();return 0;
}
//雖然PrintA函數(shù)被成功調(diào)用,但是因?yàn)閜指向nullptr,所以_a是無法讀取內(nèi)存的,因此運(yùn)行時(shí)程序會(huì)崩潰
類的作用域
類的作用域是{}中的部分,但是它只是虛擬的,這是因?yàn)轭愵愃朴趫D紙;
class Date
{
public:int _year;int _month;int _day;void init(int year, int month, int day){_year = year;_month = month;_day = day;}void print(){printf("%d-%d-%d\n", _year, _month, _day);}
};namespace date
{int _year = 2023;int _month = 5;int _day = 1;
}int main()
{Date s;/*s.print();*/printf("%d-%d-%d\n", date::_year, date::_month, date::_day);printf("%d-%d-%d\n", Date::_year, Date::_month, Date::_day);//該語句無法通過編譯system("pause");return 0;
}
?上面的代碼中,命名空間的變量可以通過作用域運(yùn)算符::來找到對(duì)應(yīng)的變量,但是類中定義的變量不能通過,其原因就是類沒有被真實(shí)創(chuàng)建,類定義的只是圖紙。
事實(shí)上不光是成員屬性不能使用作用域運(yùn)算符,成員方法也不行,這是因?yàn)閠his指針,雖然類中創(chuàng)建了成員函數(shù),但是類沒有被創(chuàng)建,沒有this指針,所以運(yùn)行崩潰。
成員函數(shù)的創(chuàng)建
定義成員函數(shù)時(shí),如果將成員函數(shù)都放在類的內(nèi)部,那么閱讀起來會(huì)非常麻煩,通常只在類中聲明,在外部定義;
class A
{
public:void PrintA();
private:int _a=10;
};void A:: PrintA()
{std::cout << _a << std::endl;
}int main()
{A _a;_a.PrintA();system("pause");return 0;
}