第一種式直接聲明:
網(wǎng)站建設(shè)哪家好,找創(chuàng)新互聯(lián)!專注于網(wǎng)頁設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、重慶小程序開發(fā)、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了梅州免費(fèi)建站歡迎大家使用!
class Student {
private:
string name;
public:
Student(string name) {
this->name = name;
}
}
//聲明:
Student lu;//不帶初始化
//帶初始化;
Student lu(huang);
Student lu = Student(huang);
//訪問方式
lu.name;
這樣的聲明方式,是將對象在棧上創(chuàng)建,棧內(nèi)存自動(dòng)管理,在執(zhí)行函數(shù)時(shí),函數(shù)內(nèi)局部變量的存儲(chǔ)單元都可以在棧上創(chuàng)建,函數(shù)執(zhí)行結(jié)束后在將這些局部變量的內(nèi)存空間回收。在棧上分配內(nèi)存空間效率很高,但是分配的內(nèi)存容量有限。
第二種使用對象指針聲明
Student *plu = new Student;//不帶初始化;
Student *plu = new Student(huang);//帶初始化;
//訪問方式
plu->name;
這樣聲明,是將對象在堆中創(chuàng)建,堆內(nèi)存代碼人員管理,new和delete配對使用。使用 new 在堆上創(chuàng)建出來的對象是匿名的,沒法直接使用,必須要用一個(gè)指針指向它,再借助指針來訪問它的成員變量或成員函數(shù)。
成員函數(shù)必須先在類體中作原型聲明,然后在類外定義,也就是說類體的位置應(yīng)在函數(shù)定義之前。因?yàn)轭愺w內(nèi)定義的函數(shù)默認(rèn)是內(nèi)聯(lián)函數(shù),一般用內(nèi)聯(lián)函數(shù)的時(shí)候才會(huì)在類內(nèi)部實(shí)現(xiàn);例子:
class Student {
private:
string name;
int age;
public:
//函數(shù)聲明
Student(string name, int age);
}
//函數(shù)定義
Student::Student(string name, int age) {
this->name = name;
this->age = age;
}
在類的內(nèi)部(定義類的代碼內(nèi)部),無論成員被聲明為 public、protected 還是 private,都是可以互相訪問的,沒有訪問權(quán)限的限制。
在類的外部(定義類的代碼之外),只能通過對象訪問成員,并且通過對象只能訪問 public 屬性的成員,不能訪問 private、protected 屬性的成員。
成員變量大都以m_
開頭,這是約定成俗的寫法,易區(qū)分。
建議在開發(fā)中不需要暴暴露出來的屬性和方法都寫成private;
給成員變量賦值的函數(shù)通常稱為 set XXX函數(shù),讀取成員變量的值的函數(shù)通常稱為 get XXX函數(shù),XXX表示變量名;類中的不寫private這些關(guān)鍵詞默認(rèn)是private;
class Student {
private:
string m_name;
public:
void setname(string name);
void getname;
}
void Student::setname(string name) {
m_name = name;//這里可以直接用m_name;
}
.....
編譯器會(huì)將成員變量和成員函數(shù)分開存儲(chǔ):分別為每個(gè)對象的成員變量分配內(nèi)存,但是所有對象都共享同一段函數(shù)代碼,節(jié)省空間,sizeof一個(gè)對象大小就是全部成員變量的總和大小;
C++和C語言的編譯方式不同。C語言中的函數(shù)在編譯時(shí)名字不變,或者只是簡單的加一個(gè)下劃線_
(不同的編譯器有不同的實(shí)現(xiàn)),c++是通過一種特殊的算法來實(shí)現(xiàn)的,對函數(shù)重命名(這個(gè)過程叫字編碼(Name Mangling));下圖是一個(gè)編譯器重命名的方式,?方法@類名.....
從上圖可以看出,成員函數(shù)最終被編譯成與對象無關(guān)的全局函數(shù),如果函數(shù)體中沒有成員變量,不用對函數(shù)做任何處理,直接調(diào)用即可。
如果有成員變量(它的作用域不是全局的),C++規(guī)定,編譯成員函數(shù)時(shí)要額外添加一個(gè)參數(shù),把當(dāng)前對象的指針傳遞進(jìn)去,通過指針來訪問成員變量(實(shí)際上傳遞的就是this指針)
void Demo::display(){
cout<<a<<endl;
}
會(huì)編譯為類似:
void new_function_name(Demo * const p){//const表示指針不能被修改;
//通過指針p來訪問a、b
cout<<p->a<<endl;
}
這樣通過傳遞對象指針就完成了成員函數(shù)和成員變量的關(guān)聯(lián)。這與我們從表明上看到的剛好相反,通過對象調(diào)用成員函數(shù)時(shí),不是通過對象找函數(shù),而是通過函數(shù)找對象。
構(gòu)造函數(shù)的調(diào)用是強(qiáng)制性的,一旦在類中定義了構(gòu)造函數(shù),那么創(chuàng)建對象時(shí)就一定要調(diào)用,不調(diào)用是錯(cuò)誤的。如果有多個(gè)重載的構(gòu)造函數(shù),那么創(chuàng)建對象時(shí)提供的實(shí)參必須和其中的一個(gè)構(gòu)造函數(shù)匹配;反過來說,創(chuàng)建對象時(shí)只有一個(gè)構(gòu)造函數(shù)會(huì)被調(diào)用;
一個(gè)類必須有構(gòu)造函數(shù),要么用戶自己定義,要么編譯器自動(dòng)生成。一旦用戶自己定義了構(gòu)造函數(shù),不管有幾個(gè),也不管形參如何,編譯器都不再自動(dòng)生成。
構(gòu)造函數(shù)定義由兩種寫法:正常函數(shù)寫法和使用構(gòu)造函數(shù)初始化列表
//第一種
Student::Student(char *name, int age){
m_name = name;
m_age = age;
}
//第二種
Student::Student(char *name, int age): m_name(name), m_age(age){}
注意????第二種:成員變量的初始化順序與初始化列表中列出的變量的順序無關(guān),它只與成員變量在類中聲明的順序有關(guān);如:
class Demo{
private:
int m_a;
int m_b;
public:
Demo(int b);
void show();
};
Demo::Demo(int b): m_b(b), m_a(m_b){
m_a = m_b;
m_b = b;
}
//錯(cuò)誤,給 m_a 賦值時(shí),m_b 還未被初始化,它的值是不確定的,所以輸出的 m_a 的值是一個(gè)奇怪的數(shù)字;給 m_a 賦值完成后才給 m_b 賦值,此時(shí) m_b 的值才是 值b。
//obj 在棧上分配內(nèi)存,成員變量的初始值是不確定的。
使用構(gòu)造函數(shù)初始化列表并沒有效率上的優(yōu)勢,但是書寫方便,而且,初始化 const 成員變量的唯一方法就是使用初始化列表,原因:為什么要用初始化列表
析構(gòu)函數(shù)(Destructor)也是一種特殊的成員函數(shù),沒有返回值,不需要程序員顯式調(diào)用(程序員也沒法顯式調(diào)用),而是在銷毀對象時(shí)自動(dòng)執(zhí)行。
class VLA{
public:
VLA(int len); //構(gòu)造函數(shù)
~VLA(); //析構(gòu)函數(shù)
private:
const int m_len; //數(shù)組長度
int *m_arr; //數(shù)組指針
int *m_p; //指向數(shù)組第i個(gè)元素的指針
};
VLA::VLA(int len): m_len(len){ //使用初始化列表來給 m_len 賦值
if(len > 0){ m_arr = new int[len]; /*分配內(nèi)存*/ }
else{ m_arr = NULL; }
}
VLA::~VLA(){
delete[] m_arr; //釋放內(nèi)存
}
通過直接用類聲明的對象在棧中,出了作用域(比如說函數(shù)return了),就會(huì)調(diào)用析構(gòu)函數(shù);在全局建的對象在.data區(qū),程序結(jié)束后才釋放; 注意?????????♂?:兩中方法調(diào)用析構(gòu)函數(shù)的順序都是先生成的后析構(gòu),后生成的先析構(gòu);
new 創(chuàng)建的對象位于堆區(qū),通過 delete 刪除時(shí)才會(huì)調(diào)用析構(gòu)函數(shù),例如在main函數(shù)中new對象然后delete對象;如果聲明了變量在堆中,不通過析構(gòu)函數(shù)釋放內(nèi)存,即使外面delete了,也只是刪除了指針,里面的空間還是被占用著,沒有被釋放掉,如上面的int[len];
此處補(bǔ)充指針知識(shí):
int a = 10;
int* p = &a;//p是指針,這個(gè)*表示是int的指針類型;
此時(shí) *p = 10//這里的*說明是這個(gè)指針指向的對象,與上面*大大不同;而p只是以一個(gè)地址
一個(gè)類的成員變量如果是另一個(gè)類的對象,就稱之為“成員對象”。包含成員對象的類叫封閉類。
創(chuàng)建封閉類的對象時(shí),它包含的成員對象也需要被創(chuàng)建,這就會(huì)引發(fā)成員對象構(gòu)造函數(shù)的調(diào)用,對于沒有默認(rèn)構(gòu)造函數(shù)的成員對象,必須要使用封閉類構(gòu)造函數(shù)的初始化列表?。。?/strong>
類名::構(gòu)造函數(shù)名(參數(shù)表): 成員變量1(參數(shù)表), 成員變量2(參數(shù)表), ...
{
//TODO:
}
一定要用初始化列表的四種情況
初始化時(shí):封閉類對象生成時(shí),先執(zhí)行所有成員對象的構(gòu)造函數(shù),然后才執(zhí)行封閉類自己的構(gòu)造函數(shù);
消亡時(shí):先執(zhí)行封閉類的析構(gòu)函數(shù),然后再執(zhí)行成員對象的析構(gòu)函數(shù),剛剛好和創(chuàng)建相反。
C++ 中的一個(gè)關(guān)鍵字,也是一個(gè) const 指針, 所以要用->
來訪問成員變量或成員函數(shù)。它指向當(dāng)前對象,通過它可以訪問當(dāng)前對象的所有成員。
this的本質(zhì):this 實(shí)際上是成員函數(shù)的一個(gè)形參,在調(diào)用成員函數(shù)時(shí)將對象的地址作為實(shí)參傳遞給 this。不過 this 這個(gè)形參是隱式的,它并不出現(xiàn)在代碼中,而是在編譯階段由編譯器默默地將它添加到參數(shù)列表中。
上述中函數(shù)編譯原理:成員函數(shù)最終被編譯成與對象無關(guān)的普通函數(shù),除了成員變量,會(huì)丟失所有信息,所以編譯時(shí)要在成員函數(shù)中添加一個(gè)額外的參數(shù),把當(dāng)前對象的首地址傳入,以此來關(guān)聯(lián)成員函數(shù)和成員變量。這個(gè)額外的參數(shù),實(shí)際上就是 this,它是成員函數(shù)和成員變量關(guān)聯(lián)的橋梁。
static修飾成員變量:
一個(gè)類中可以有一個(gè)或多個(gè)靜態(tài)成員變量,所有的對象都共享這些靜態(tài)成員變量,都可以引用它。
static 成員變量和普通 static 變量一樣,都在內(nèi)存分區(qū)中的全局?jǐn)?shù)據(jù)區(qū)分配內(nèi)存,到程序結(jié)束時(shí)才釋放。這就意味著,static 成員變量不隨對象的創(chuàng)建而分配內(nèi)存,也不隨對象的銷毀而釋放內(nèi)存。而普通成員變量在對象創(chuàng)建時(shí)分配內(nèi)存,在對象銷毀時(shí)釋放內(nèi)存。
靜態(tài)成員變量必須初始化,而且只能在類體外進(jìn)行。例如:int Student::m_total = 10;初始化時(shí)可以賦初值,也可以不賦值。如果不賦值,那么會(huì)被默認(rèn)初始化為 0。全局?jǐn)?shù)據(jù)區(qū)的變量都有默認(rèn)的初始值 0,而動(dòng)態(tài)數(shù)據(jù)區(qū)(堆區(qū)、棧區(qū))變量的默認(rèn)值是不確定的,一般認(rèn)為是垃圾值。
靜態(tài)成員變量既可以通過對象名訪問,也可以通過類名訪問,但要遵循 private、protected 和 public 關(guān)鍵字的訪問權(quán)限限制。當(dāng)通過對象名訪問時(shí),對于不同的對象,訪問的是同一份內(nèi)存。
static修飾成員函數(shù):
靜態(tài)成員函數(shù)與普通成員函數(shù)的根本區(qū)別在于:普通成員函數(shù)有 this 指針,可以訪問類中的任意成員;而靜態(tài)成員函數(shù)沒有 this 指針,只能訪問靜態(tài)成員(包括靜態(tài)成員變量和靜態(tài)成員函數(shù))
原因:編譯器在編譯一個(gè)普通成員函數(shù)時(shí),會(huì)隱式地增加一個(gè)形參 this,并把當(dāng)前對象的地址賦值給 this,所以普通成員函數(shù)只能在創(chuàng)建對象后通過對象來調(diào)用,因?yàn)樗枰?dāng)前對象的地址。而靜態(tài)成員函數(shù)可以通過類來直接調(diào)用,編譯器不會(huì)為它增加形參 this,它不需要當(dāng)前對象的地址,所以不管有沒有創(chuàng)建對象,都可以調(diào)用靜態(tài)成員函數(shù),所以靜態(tài)成員函數(shù)也無法訪問普通成員變量,只能訪問靜態(tài)成員(在全局)。
const成員變量:加上 const 關(guān)鍵字。初始化 const 成員變量只有一種方法,就是通過構(gòu)造函數(shù)的初始化列表
const成員函數(shù): const 成員函數(shù)可以使用類中的所有成員變量,但是不能修改它們的值,這種措施主要還是為了保護(hù)數(shù)據(jù)而設(shè)置的。一般類中的get函數(shù)都設(shè)置為常成員函數(shù),只讀不給改;
函數(shù)開頭的 const 用來修飾函數(shù)的返回值,表示返回值是 const 類型,也就是不能被修改,例如const char * getname()
。
函數(shù)頭部的結(jié)尾加上 const 表示常成員函數(shù),這種函數(shù)只能讀取成員變量的值,而不能修改成員變量的值,例如char * getname() const
class Student {
public:
Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score) {}//方法實(shí)現(xiàn)都不寫;
char *getname() const;
prviate:
char *m_name;
int m_age;
float m_score;
};
char* Student::getname() const {
return m_name;
}//方法實(shí)現(xiàn)都不寫;
const對象: const 也可以用來修飾對象,稱為常對象。一旦將對象定義為常對象之后,就只能調(diào)用類的 const 成員(包括 const 成員變量和 const 成員函數(shù))了,因?yàn)榉?const 成員可能會(huì)修改對象的數(shù)據(jù)(編譯器也會(huì)這樣假設(shè)),C++禁止這樣做。
借助友元(friend),可以使得其他類中的成員函數(shù)以及全局范圍內(nèi)的函數(shù)訪問當(dāng)前類的 private 成員。在當(dāng)前類以外定義的、不屬于當(dāng)前類的函數(shù)也可以在類中聲明,但要在前面加 friend 關(guān)鍵字,這樣就構(gòu)成了友元函數(shù)。友元函數(shù)可以是不屬于任何類的 非成員函數(shù),也可以是其他類的成員函數(shù)。
class Student{
public:
Student(char *name, int age, float score);
public:
friend void show(Student *pstu); //將show()聲明為友元函數(shù)
private:
char *m_name;
int m_age;
float m_score;
};
//非成員函數(shù)
void show(Student *pstu){//屬于全局函數(shù),通過參數(shù)傳遞對象,可以訪問private成員變量
cout<<pstu->m_name<<"的年齡是 "<<pstu->m_age<<",成績是 "<<pstu->m_score<<endl;
}
class Address; //一定要提前聲明Address類
//聲明Student類
class Student{
public:
Student(char *name, int age, float score);
public:
void show(Address *addr);//要使用的類,前面有聲明address所以不會(huì)報(bào)錯(cuò)?。。。。。。。。。。。。。。。?!
private:
char *m_name;
int m_age;
float m_score;
};
//聲明Address類
class Address{
private:
char *m_province; //省份
char *m_city; //城市
char *m_district; //區(qū)(市區(qū))
public:
Address(char *province, char *city, char *district);
//將Student類中的成員函數(shù)show()聲明為友元函數(shù)
friend void Student::show(Address *addr);//!?。。。。。。。。。。。。。。。。。?};
//實(shí)現(xiàn)Student類
Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score){ }
void Student::show(Address *addr){
cout<<m_name<<"的年齡是 "<<m_age<<",成績是 "<<m_score<<endl;
cout<<"家庭住址:"<<addr->m_province<<"省"<<addr->m_city<<"市"<<addr->m_district<<"區(qū)"<<endl;
}
友元類:
將類 B 聲明為類 A 的友元類,那么類 B 中的所有成員函數(shù)都是類 A 的友元函數(shù),可以訪問類 A 的所有成員,包括 public、protected、private 屬性的
class Address; //提前聲明Address類
//聲明Student類
class Student{
public:
Student(char *name, int age, float score);
public:
void show(Address *addr);
private:
char *m_name;
int m_age;
float m_score;
};
//聲明Address類
class Address{
public:
Address(char *province, char *city, char *district);
public:
//將Student類聲明為Address類的友元類
friend class Student;
private:
char *m_province; //省份
char *m_city; //城市
char *m_district; //區(qū)(市區(qū))
};
//實(shí)現(xiàn)Student類
Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score){ }
void Student::show(Address *addr){
cout<<m_name<<"的年齡是 "<<m_age<<",成績是 "<<m_score<<endl;
cout<<"家庭住址:"<<addr->m_province<<"省"<<addr->m_city<<"市"<<addr->m_district<<"區(qū)"<<endl;
}
//實(shí)現(xiàn)Address類
Address::Address(char *province, char *city, char *district){
m_province = province;
m_city = city;
m_district = district;
}
ps: 其實(shí)類也是一種作用域 , 普通的成員只能通過對象(可以是對象本身,也可以是對象指針或?qū)ο笠茫﹣碓L問,靜態(tài)成員既可以通過對象訪問,又可以通過類訪問,而 typedef 定義的類型只能通過類來訪問
C++中,struct 類似于 class,既可以包含成員變量,又可以包含成員函數(shù)。
C++中的 struct 和 class 基本是通用的,唯有幾個(gè)細(xì)節(jié)不同:
建議使用 class 來定義類,而使用 struct 來定義結(jié)構(gòu)體,這樣做語義更加明確
分享標(biāo)題:初識(shí)C++02:類和對象
文章源于:http://chinadenli.net/article18/dsoipgp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信公眾號(hào)、關(guān)鍵詞優(yōu)化、用戶體驗(yàn)、網(wǎng)站營銷、網(wǎng)站導(dǎo)航、域名注冊
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)