做窗簾店的網(wǎng)站關(guān)鍵詞競(jìng)價(jià)排名名詞解釋
目錄
1.基本函數(shù)
2.淺拷貝和深拷貝
3.初始化列表
4.const關(guān)鍵字的使用
5.靜態(tài)成員變量和成員函數(shù)
6.C++對(duì)象模型
7.友元
8.自動(dòng)類型轉(zhuǎn)換
9.繼承
1.基本函數(shù)
(1)構(gòu)造函數(shù),這個(gè)需要注意的就是我們?nèi)绻褂妙惷永ㄌ?hào),括號(hào)里面加參數(shù)的方式這樣的寫(xiě)法不是在調(diào)用構(gòu)造函數(shù),而是在創(chuàng)建一個(gè)匿名對(duì)象;
using namespace std;
class cgril
{
public:string m_name;int m_age;char m_memo[600];cgril(){initdata();cout << "這里調(diào)用了cgril()構(gòu)造函數(shù)" << endl;}cgril(string name)//一個(gè)姓名參數(shù)的初始化函數(shù){initdata();cout << "調(diào)用了cgril(string name)構(gòu)造函數(shù)" << endl;m_name = name;}cgril(int age)//一個(gè)年齡參數(shù)的初始化函數(shù){initdata();cout << "調(diào)用了構(gòu)造函數(shù)" << endl;m_age = age;}cgril(string name, int age){initdata();cout << "這里的調(diào)用了構(gòu)造函數(shù)" << endl;m_name = name;m_age = age;}void initdata(){m_name.clear();m_age = 0;memset(m_memo, 0, sizeof(m_memo));}void show(){cout << "姓名:" << m_name << ",年齡:" << m_age << ",備注:" << m_memo << endl;}
};
(2)下面的兩種寫(xiě)法看似一樣,實(shí)際上是截然不同的:
第一行和23兩行可以實(shí)現(xiàn)相同的效果,但是這個(gè)第一行是屬于顯示的調(diào)用構(gòu)造函數(shù),執(zhí)行一次構(gòu)造函數(shù)和析構(gòu)函數(shù);
23行可以達(dá)到這個(gè)效果,但是會(huì)執(zhí)行兩次構(gòu)造函數(shù)和析構(gòu)函數(shù),因?yàn)檫@個(gè)cgri("張三",20)執(zhí)行的時(shí)候,會(huì)生成一個(gè)臨時(shí)對(duì)象,賦值給這個(gè)gril對(duì)象,相當(dāng)于是賦值函數(shù),因?yàn)橛羞@個(gè)臨時(shí)對(duì)象的參與,所以就會(huì)執(zhí)行兩次這個(gè)構(gòu)造函數(shù),一次是構(gòu)造gril這個(gè)對(duì)象,一次是構(gòu)造臨時(shí)對(duì)象;
(3)下面的就是兩個(gè)拷貝構(gòu)造函數(shù),第一個(gè)是沒(méi)有重載的,第二個(gè)是重載的;
cgril(const cgril& gg)
{m_name = gg.m_name;m_age = gg.m_age;cout << "調(diào)用沒(méi)有重載的拷貝構(gòu)造函數(shù)" << endl;
}
cgril(const cgril& gg1,int ii)
{m_name = gg1.m_name;m_age = gg1.m_age - ii;cout << "調(diào)用重載的拷貝構(gòu)造函數(shù)" << endl;
}
我們把這個(gè)沒(méi)有重載的函數(shù)注釋掉,發(fā)現(xiàn)這個(gè)還是可以實(shí)現(xiàn)把g1的內(nèi)容拷貝給g2的,這個(gè)時(shí)候他沒(méi)有去調(diào)用這個(gè)重載的函數(shù),因?yàn)檫@個(gè)重載的函數(shù)需要有2個(gè)參數(shù),但是我們調(diào)用的時(shí)候,只傳遞一個(gè)參數(shù)?,如果這個(gè)函數(shù)的第二個(gè)參數(shù)存在缺省參數(shù),編譯器是會(huì)去調(diào)用的,但是這個(gè)時(shí)候沒(méi)有缺省參數(shù),依然可以實(shí)現(xiàn)拷貝,這個(gè)就說(shuō)明如果類里面定義了重載的拷貝構(gòu)造函數(shù)卻沒(méi)有提供這個(gè)默認(rèn)的拷貝構(gòu)造函數(shù),這個(gè)時(shí)候編譯器會(huì)自動(dòng)提供拷貝構(gòu)造函數(shù);
cgril g1;
g1.m_name = "張三";
g1.m_age = 18;
cgril g2(g1);
g2.show();
(4)編譯器的優(yōu)化問(wèn)題,就是返回值如果是一個(gè)類的時(shí)候,可能會(huì)調(diào)用拷貝構(gòu)造函數(shù)(這個(gè)和變編譯器有關(guān)),有的編譯器就會(huì)調(diào)用這個(gè)拷貝構(gòu)造函數(shù),有的會(huì)把這個(gè)步驟給優(yōu)化掉,直接使用這個(gè)對(duì)象,只不過(guò)給這個(gè)對(duì)象換了一個(gè)名字罷了;
cgril func()
{cgril gg;gg.m_name = "張三";gg.m_age = 18;return gg;
}
int main()
{cgril ggg = func();ggg.show();
}
2.淺拷貝和深拷貝
(1)我們這個(gè)編譯器默認(rèn)提供的拷貝構(gòu)造函數(shù)就是一個(gè)淺拷貝,如果指針p1指向一塊空間,拷貝給指針p2之后,兩個(gè)指針就會(huì)指向同一塊空間,釋放一個(gè)空間另外的一個(gè)指針的指向就不存在了,也就是說(shuō)另外的一個(gè)指針就會(huì)變成野指針,而且對(duì)于這個(gè)一個(gè)指針數(shù)據(jù)的修改同樣會(huì)影響另外的一個(gè)指針數(shù)據(jù);
(2)深拷貝解決了淺拷貝的弊端,就是如果想拷貝,不是原來(lái)的那樣直接指向同一塊空間,而是開(kāi)辟出新的空間,把這個(gè)原來(lái)的空間的內(nèi)容給釋放掉,這樣的話兩個(gè)指針各自操控各自的區(qū)域,就不會(huì)出現(xiàn)上面的野指針的問(wèn)題了;
3.初始化列表
(1)基本寫(xiě)法
這個(gè)初始化列表是跟在這個(gè)構(gòu)造函數(shù)的后面的,如果使用了初始化列表,就不能再這個(gè)構(gòu)造函數(shù)里面再次給這個(gè)成員變量賦值,因?yàn)檫@個(gè)時(shí)候構(gòu)造函數(shù)里面的賦值就會(huì)覆蓋掉原來(lái)的初始化列表里面的初始值;
(2)初始化列表里面的數(shù)值可以是具體的值,也可以是這個(gè)參數(shù),表達(dá)式等等;
cgril(string name, int age):m_name(name),m_age(age)
{cout << "這里的調(diào)用了構(gòu)造函數(shù)" << endl;
}int main()
{cgril g1("李四", 18);g1.show();return 0;
}
這個(gè)是實(shí)例里面,我們就是使用這個(gè)形參作為初始化列表里面的初始值;
我們還可以在這個(gè)初始化列表的這個(gè)括號(hào)里面添加文字,進(jìn)行這個(gè)表達(dá)式的書(shū)寫(xiě),例如,我們可以對(duì)于這個(gè)年齡進(jìn)行加減操作,對(duì)于這個(gè)名字的前面加上一些修飾語(yǔ),如下所示:
cgril(string name, int age):m_name("高大威猛的" + name), m_age(age + 6)
{cout << "這里的調(diào)用了構(gòu)造函數(shù)" << endl;
}
(3)當(dāng)這個(gè)初始化列表的成員是類的時(shí)候,使用初始化列表調(diào)用的是成員類的拷貝構(gòu)造函數(shù),而賦值是先創(chuàng)建成員類的對(duì)象,這個(gè)時(shí)候調(diào)用的是成員類的普通構(gòu)造函數(shù),然后再賦值;
下面的這段代碼有助于我們了解兩者之間的區(qū)別:
class cboy
{
public:string m_xm;//男朋友的姓名cboy(){m_xm.clear();cout << "調(diào)用cboy()普通構(gòu)造函數(shù)" << endl;}cboy(string name){m_xm = name;cout << "調(diào)用只有一個(gè)參數(shù)的cboy(string name)構(gòu)造函數(shù)" << endl;}cboy(const cboy& bb){m_xm = bb.m_xm;cout << "調(diào)用了cboy(const cboy& bb)拷貝構(gòu)造函數(shù)" << endl;}
};
class cgril
{
public:string m_name;int m_age;cboy m_boy;cgril(){cout << "這里調(diào)用了cgril()構(gòu)造函數(shù)" << endl;}cgril(string name) //一個(gè)姓名參數(shù)的初始化函數(shù){cout << "調(diào)用了cgril(string name)構(gòu)造函數(shù)" << endl;m_name = name;}cgril(int age) //一個(gè)年齡參數(shù)的初始化函數(shù){cout << "調(diào)用了cgril(int age)構(gòu)造函數(shù)" << endl;m_age = age;}cgril(string name, int age, cboy boy):m_name(name), m_age(age){m_boy.m_xm = boy.m_xm;cout << "調(diào)用cgril(string name, int age, cboy boy)構(gòu)造函數(shù)" << endl;}void show(){cout << "姓名:" << m_name << ",年齡:" << m_age<<",男朋友:"<<m_boy.m_xm << endl;}
};
int main()
{cboy boy("張三");cgril gg("李四", 18, boy);gg.show();return 0;
}
這個(gè)就是上面的代碼的執(zhí)行情況, 執(zhí)行主函數(shù)里面的第一行的時(shí)候就會(huì)調(diào)用cboy類里面的構(gòu)造函數(shù),執(zhí)行主函數(shù)里面的第二行的時(shí)候,因?yàn)檫@個(gè)實(shí)參boy是一個(gè)對(duì)象,傳遞給形參的時(shí)候使用的是值傳遞,所以這個(gè)時(shí)候就會(huì)執(zhí)行這個(gè)拷貝構(gòu)造函數(shù),這個(gè)構(gòu)造函數(shù)就是實(shí)參的內(nèi)容傳遞給形參;
用類創(chuàng)建對(duì)象的時(shí)候,先去初始化構(gòu)造函數(shù)的形參對(duì)象,然后再去初始化類的成員;控制臺(tái)輸出的第四行日志是cgril的對(duì)象gg創(chuàng)建的時(shí)候被調(diào)用的,這個(gè)很好理解;
當(dāng)我們把這個(gè)boy形參改為引用傳參,而不是原來(lái)的值傳參的時(shí)候,這個(gè)時(shí)候就不會(huì)調(diào)用這個(gè)拷貝構(gòu)造函數(shù)了,因?yàn)檫@個(gè)引用的話使用的是和實(shí)現(xiàn)相同的東西,只不過(guò)是找了一個(gè)別名罷了;
上面介紹的所有內(nèi)容,這個(gè)超女的男朋友進(jìn)行這個(gè)初始化列表的時(shí)候,并沒(méi)有走這個(gè)初始化列表,相反這個(gè)是先執(zhí)行構(gòu)造函數(shù),在這個(gè)函數(shù)體里面進(jìn)行初始化,這個(gè)是兩個(gè)步驟;
下面我們使用初始化列表對(duì)于這個(gè)超女類的成員進(jìn)行初始化操作:
這個(gè)時(shí)候我們發(fā)現(xiàn)當(dāng)我們使用初始化列表的時(shí)候,調(diào)用的是成員類的拷貝構(gòu)造函數(shù),這個(gè)時(shí)候?qū)ο蟮某跏蓟唾x值是兩步操作,使用初始化列表,對(duì)象的初始化和賦值就是一步操作;
這個(gè)時(shí)候?qū)Ρ戎暗臎](méi)有使用初始化列表的情況,顯示對(duì)于這個(gè)形參執(zhí)行的是普通構(gòu)造函數(shù),然后在這個(gè)構(gòu)造函數(shù)體里面進(jìn)行賦值,這個(gè)時(shí)候相信你就可以理解最開(kāi)始的時(shí)候這句話的意思了:
當(dāng)這個(gè)初始化列表的成員是類的時(shí)候,使用初始化列表調(diào)用的是成員類的拷貝構(gòu)造函數(shù),而賦值是先創(chuàng)建成員類的對(duì)象,這個(gè)時(shí)候調(diào)用的是成員類的普通構(gòu)造函數(shù),然后再賦值;
可見(jiàn)這個(gè)一個(gè)類的成員變量是一個(gè)類的時(shí)候這個(gè)初始化列表和普通的賦值初始化有以下的區(qū)別:
第一就是這個(gè)調(diào)用的函數(shù)不一樣,賦值進(jìn)行初始化時(shí)候,調(diào)用的是子類的普通構(gòu)造函數(shù),然后執(zhí)行這個(gè)函數(shù)體里面的賦值語(yǔ)句對(duì)于這個(gè)成員變量進(jìn)行賦值;但是這個(gè)初始化列表的方法就是調(diào)用拷貝構(gòu)造函數(shù);
第二點(diǎn)就是效率不一樣,普通的賦值初始化就是先創(chuàng)建,初始化之后賦值,但是這個(gè)初始化列表是初始化和賦值是一步就完成的;(請(qǐng)讀者下去慢慢體會(huì)兩者的區(qū)別)
(4)當(dāng)這個(gè)類的成員是常量或者是引用的時(shí)候,只能使用初始化列表進(jìn)行初始化操作;
常量指的就是這個(gè)成員變量的前面加上const關(guān)鍵字進(jìn)行修飾,這個(gè)時(shí)候的成員變量必須在定義的時(shí)候進(jìn)行初始化,而我們的這個(gè)先構(gòu)造再賦值就不符合這個(gè)條件,只能使用初始化列表的方式進(jìn)行初始化;例如,下面的這兩種情況都需要使用初始化列表的方式進(jìn)行初始化;
4.const關(guān)鍵字的使用
(1)下面我們對(duì)于這個(gè)const的使用會(huì)在下面的這個(gè)代碼基礎(chǔ)上面進(jìn)行修改和調(diào)整;
class cgril
{
public:string m_name;int m_age;cgril(const string& name, int age){m_name = name;m_age = age;cout << "調(diào)用兩個(gè)參數(shù)的cgril(const string& name, int age)構(gòu)造函數(shù)" << endl;}void show() const{cout << "姓名:" << m_name << ",年齡:" << m_age << endl;}
};int main()
{cgril g("張三", 18);g.show();return 0;
}
?這個(gè)代碼里面有一個(gè)show函數(shù),這個(gè)函數(shù)的作用就是打印輸出這個(gè)名字和年齡的值,我們是不會(huì)對(duì)于這個(gè)數(shù)值進(jìn)行修改的,這樣的情況下我們就可以在這個(gè)函數(shù)的后面加上const進(jìn)行修飾,表示這個(gè)函數(shù)不會(huì)對(duì)于這個(gè)成員變量的值進(jìn)行修改;
這個(gè)時(shí)候我們?nèi)绻谶@個(gè)函數(shù)里面對(duì)于這個(gè)數(shù)值進(jìn)行修改,程序就會(huì)報(bào)錯(cuò);
(2)函數(shù)的相關(guān)調(diào)用
非const修飾的函數(shù)可以調(diào)用const修飾的和非const修飾的,但是const修飾的函數(shù)只能調(diào)用const修飾的函數(shù);
同理,我們對(duì)于這個(gè)函數(shù)可以使用const進(jìn)行修飾,對(duì)于這個(gè)對(duì)象,我們也可以使用const進(jìn)行修飾,這樣的對(duì)象叫做常對(duì)象,常對(duì)象被這個(gè)const修飾,因此常對(duì)象只能調(diào)用const修飾的函數(shù),不能調(diào)用非const修飾的函數(shù);
我們?cè)谶\(yùn)行的時(shí)候會(huì)發(fā)現(xiàn),這個(gè)會(huì)執(zhí)行構(gòu)造函數(shù),但是構(gòu)造函數(shù)沒(méi)有const修飾,依然可以執(zhí)行通過(guò),這個(gè)時(shí)候我們就可以理解為常對(duì)象調(diào)用const修飾的函數(shù)針對(duì)的是我們自己定義的函數(shù),這個(gè)構(gòu)造函數(shù)編譯器也會(huì)提供,所以可以調(diào)用,如果我們?cè)谶@個(gè)構(gòu)造函數(shù)后面加上const修飾,反而程序會(huì)報(bào)錯(cuò),這個(gè)是因?yàn)樵跇?gòu)造函數(shù)后面加上const是非法的;
4.this指針
(1)我們通過(guò)下面的這段代碼逐步過(guò)渡到thsi指針,這個(gè)代碼實(shí)現(xiàn)的就是兩個(gè)超女的顏值比較,然后輸出顏值更高的,我們使用yz這個(gè)整型變量表示顏值;
class cgril
{
public:string m_name;int m_yz;//這個(gè)代表的是顏值,我們使用整形數(shù)字代替,1表示顏值最高,3表示顏值最低;cgril(const string& name, int yz){m_name = name;m_yz = yz;}void show() const{cout << "我是" << m_name << ",顏值最高的超女" << endl;}
};
const cgril& pk(const cgril& gg1, const cgril& gg2)
{if (gg1.m_yz < gg2.m_yz){return gg1;}else{return gg2;}
}
int main()
{cgril g1("張三", 1);cgril g2("李四", 2);cgril g3 = pk(g1, g2);g3.show();return 0;
}
(2)這個(gè)代碼是可以實(shí)現(xiàn)顏值比較的功能的,但是他沒(méi)有顯示出來(lái)C++的優(yōu)勢(shì),下面我們使用this指針實(shí)現(xiàn)以下這個(gè)功能;
class cgril
{
public:string m_name;int m_yz;//這個(gè)代表的是顏值,我們使用整形數(shù)字代替,1表示顏值最高,3表示顏值最低;cgril(const string& name, int yz){m_name = name;m_yz = yz;}void show() const{cout << "我是" << m_name << ",顏值最高的超女" << endl;}const cgril& pk(const cgril& gg) const{if (gg.m_yz < m_yz){return gg;}else{return *this;}}
};
int main()
{cgril g1("張三", 1);cgril g2("李四", 2);const cgril& g3 = g1.pk(g2);g3.show();return 0;
}
這個(gè)里面更符合C++的編程邏輯,就是使用thsi指針,這個(gè)比較顏值的函數(shù)不再放在類的外面,而是放在類的里面作為一個(gè)成員函數(shù),這樣的成員函數(shù)實(shí)際上在傳參的時(shí)候都傳遞過(guò)去了一個(gè)this指針,只不過(guò)不會(huì)顯示,誰(shuí)調(diào)用的成員函數(shù),這個(gè)this指針就會(huì)指向誰(shuí),這個(gè)地方好像this指針的好處還顯示不出來(lái);
我們上面是比較的兩個(gè)超女的顏值,因此這個(gè)C語(yǔ)言風(fēng)格的比較判斷還很簡(jiǎn)潔,并不是很復(fù)雜,但是當(dāng)我們需要比較五個(gè)超女的顏值的時(shí)候可能這個(gè)C++里面的thsi指針就會(huì)更具有優(yōu)勢(shì);
這個(gè)時(shí)候我們的成員函數(shù)不變,但是這樣寫(xiě)這個(gè)函數(shù)的調(diào)用就會(huì)很能凸顯這個(gè)this指針的精妙了;
這個(gè)時(shí)候我們的寫(xiě)法就可以使用這個(gè)指針只用一個(gè)式子就可以比較這五個(gè)的顏值;?
5.靜態(tài)成員變量和成員函數(shù)
(1)靜態(tài)成員變量就是在我們寫(xiě)的這個(gè)普通成員變量的前面加上const關(guān)鍵字,普通的成員變量就變成了靜態(tài)成員變量;
class cgril
{
public:string m_name;static int m_age;cgril(const string& name, int age){m_name = name;m_age = age;}void showname(){cout << "姓名:" << m_name << endl;}void showage(){cout << "年齡:" << m_age << endl;}
};
int cgril::m_age = 0;
int main()
{cgril gg("張三", 18);gg.showname();gg.showage();return 0;
}
(2)上面的程序我們把這個(gè)m_age的成員變量定義為靜態(tài)的成員變量,這個(gè)時(shí)候我們?cè)谶@個(gè)全局區(qū)里面必須對(duì)于這個(gè)靜態(tài)的成員變量進(jìn)行初始化,需要指定這個(gè)作用域(實(shí)際上就是類名),對(duì)于這個(gè)普通的成員變量,我們不能在這個(gè)主函數(shù)里面直接打印輸出結(jié)果,但是對(duì)于這個(gè)靜態(tài)的成員變量,我們可以加上他的作用域之后直接打印輸出結(jié)果;
這個(gè)時(shí)候我們就可以發(fā)現(xiàn),這個(gè)這個(gè)靜態(tài)成員變量是可以直接打印的,但是對(duì)于這個(gè)普通的成員變量,如果我們直接打印,就會(huì)報(bào)錯(cuò),這個(gè)是因?yàn)檫@個(gè)普通的成員變量必須使用創(chuàng)建得對(duì)象進(jìn)行調(diào)用,我們的靜態(tài)成員變量是可以直接進(jìn)行打印輸出結(jié)果的;
(3)關(guān)于靜態(tài)成員函數(shù)
我們上面的靜態(tài)成員變量可以直接使用,不需要?jiǎng)?chuàng)建對(duì)象,同理,如果我們把這個(gè)函數(shù)設(shè)置成成員函數(shù),我們也是可以直接調(diào)用的,對(duì)于普通的成員函數(shù),我們也是需要?jiǎng)?chuàng)建對(duì)象之后使用對(duì)象調(diào)用函數(shù);
關(guān)于這個(gè)靜態(tài)成員變量是放在這個(gè)全局區(qū)進(jìn)行定義初始化的,所以這個(gè)成員變量的作用就和這個(gè)全局變量基本是一樣的,只有程序結(jié)束的時(shí)候這個(gè)成員變量才會(huì)被銷毀;
?這個(gè)靜態(tài)成員變量只有一份,所以即使我們對(duì)于這個(gè)靜態(tài)的成員變量多次進(jìn)行賦值,最后的時(shí)候這個(gè)成員變量的值只會(huì)保留一份,但是普通的成員變量的值還是顯示不同的,但是這個(gè)靜態(tài)成員變量的值只有一份,所以打印結(jié)果顯示的靜態(tài)的成員變量都是相同的數(shù)值,因?yàn)檫@個(gè)最新的20已經(jīng)把前面的兩個(gè)年齡全部覆蓋掉了;
(4)靜態(tài)成員變量函數(shù)的訪問(wèn)權(quán)限
我們前面使用的這個(gè)是把年齡這個(gè)成員變量靜態(tài)化,函數(shù)也是把這個(gè)打印年齡的成員函數(shù)靜態(tài)化,這個(gè)時(shí)候我們?cè)陟o態(tài)成員函數(shù)里面只能調(diào)用;
另外這個(gè)靜態(tài)成員函數(shù)沒(méi)有this指針,在非靜態(tài)成員函數(shù)里面可以訪問(wèn)靜態(tài)成員變量;
私有的靜態(tài)成員無(wú)法被類外面的成員訪問(wèn),這個(gè)想要驗(yàn)證的話也是很簡(jiǎn)單的,我們把這個(gè)定義的靜態(tài)的成員變量挪動(dòng)到public的上面去,這個(gè)時(shí)候沒(méi)有范圍修飾的靜態(tài)成員變量的默認(rèn)屬性就是私有的,這個(gè)時(shí)候我們?nèi)绻谥骱瘮?shù)里面對(duì)于這個(gè)成員變量進(jìn)行調(diào)用就會(huì)報(bào)錯(cuò);(這個(gè)也是靜態(tài)成員變量區(qū)別于全局變量的重要原因)
6.C++對(duì)象模型
(1)這個(gè)存在一個(gè)叫做指針表,通過(guò)這個(gè)指針表就可以找到對(duì)象成員的地址,對(duì)象成員的地址在物理上面不一定是連續(xù)的,但是這個(gè)指針表的指針一定是連續(xù)的,并且這個(gè)指針表的大小是固定的,通過(guò)這個(gè)指針表我們就可以找到這個(gè);類里面的成員的地址;
(2)靜態(tài)的成員變量屬于類,不屬于對(duì)象,所以這個(gè)靜態(tài)的成員變量是獨(dú)特一份的,不會(huì)因?yàn)檫@個(gè)創(chuàng)建的對(duì)象的多少影響到靜態(tài)的成員變量占用的內(nèi)存空間的大小;
(3)成員函數(shù)也是屬于類的,無(wú)論這個(gè)對(duì)象怎么變,這個(gè)成員函數(shù)都是不受影響的,它的大小也不會(huì)計(jì)算在這個(gè)對(duì)象里面,他是獨(dú)立于對(duì)象存儲(chǔ)的;
(4)成員函數(shù)的地址和成員變量的地址明顯不在一起,但是成員函數(shù)的地址和這個(gè)普通函數(shù)的地址是在一塊的;
(5)在我們程序員看來(lái)這個(gè)類里面的東西好像是完整的,實(shí)際上這個(gè)成員變量和成員函數(shù)都是分散存儲(chǔ)在這個(gè)內(nèi)存里面的,所以在這個(gè)C++內(nèi)部,一定有一個(gè)東西用來(lái)記錄這個(gè)成員的地址,這個(gè)東西就是我們上面提及到的指針表;通過(guò)這個(gè)指針表我們就可以找到這個(gè)成員變量和成員函數(shù)的地址;
(6)如果成員函數(shù)里面沒(méi)有用到成員變量,這個(gè)時(shí)候我們可以使用空指針調(diào)用這個(gè)成員函數(shù),但是如果這個(gè)成員函數(shù)里面使用到了這個(gè)成員變量,我們就需要進(jìn)行判斷這個(gè)指針是否為空;
換言之,通俗的講,就是這個(gè)我們?cè)跊](méi)有創(chuàng)建對(duì)象的時(shí)候,調(diào)用函數(shù),當(dāng)這個(gè)函數(shù)里面嗎,當(dāng)這個(gè)函數(shù)里面沒(méi)有使用到成員變量的時(shí)候,我們是可以對(duì)于這個(gè)函數(shù)進(jìn)行調(diào)用的;?
但是當(dāng)這個(gè)函數(shù)里面使用了成員變量的時(shí)候,而且沒(méi)有創(chuàng)建對(duì)象,我們使用這個(gè)成員變量就相當(dāng)于這個(gè)使用空指針,這個(gè)時(shí)候如果我們直接運(yùn)行就會(huì)報(bào)錯(cuò),這個(gè)時(shí)候就需要對(duì)于這個(gè)指針進(jìn)行判斷是否是空指針;
(7)對(duì)象的地址是第一個(gè)非靜態(tài)成員變量的地址,如果沒(méi)有非靜態(tài)的成員變量,編譯器會(huì)隱含的增加一個(gè)字節(jié)作為占位成員;
7.友元
(1)友元實(shí)際上就是當(dāng)我們沒(méi)有辦法訪問(wèn)某個(gè)私有成員變量的時(shí)候,我們可以把這個(gè)函數(shù)設(shè)置為這個(gè)類的友元函數(shù),這樣的話我們的函數(shù)就可以訪問(wèn)這個(gè)類的私有成員變量;
using namespace std;
class cgril;
class cboy
{
public:void func1(const cgril& g);void func2(const cgril& gg);
};class cgril
{friend void cboy::func1(const cgril& g);friend void cboy::func2(const cgril& gg);
public:string m_name;void showname(){cout << "姓名:" << m_name << endl;}cgril(){m_name = "張三";m_age = 18;}
private:int m_age;void showage(){cout << "年齡:" << m_age << endl;}
};void cboy::func1(const cgril& g) { cout << g.m_name << endl; }
void cboy::func2(const cgril& gg) { cout << gg.m_age<< endl; }int main()
{cgril g;cboy b;b.func1(g);b.func2(g);return 0;
}
(2)我們知道的都是對(duì)于一個(gè)函數(shù)使用自己的類里面的某個(gè)私有成員,這個(gè)時(shí)候我們可以把這個(gè)函數(shù)放到類的里面作為友元函數(shù),這個(gè)函數(shù)的作用就是讓我們可以使用這個(gè)類里面的私有成員;
上面的是一個(gè)友元函數(shù)的情況,涉及到兩個(gè)類之間的相互調(diào)用,這個(gè)時(shí)候就是函數(shù)的聲明和定義過(guò)程比較繁瑣;這個(gè)時(shí)候我們?cè)谶@個(gè)cboy的類里面就可以調(diào)用cgril類里面的東西了;這個(gè)友元函數(shù)的作用就是我們可以調(diào)用其他類里面的函數(shù);
8.自動(dòng)類型轉(zhuǎn)換
(1)下面的就展示了幾種自定義類型數(shù)據(jù)的轉(zhuǎn)換方法,例如這個(gè)顯示轉(zhuǎn)換,隱式轉(zhuǎn)換,先創(chuàng)建對(duì)象,再構(gòu)建臨時(shí)變量,再去賦值;
class cgril
{
public:int m_bh;string m_name;double m_weight;cgril(){m_bh = 0;m_name.clear();m_weight = 0;}void show(){cout << "編號(hào):" << m_bh << "姓名:" << m_name << "體重:" << endl;}cgril(int bh)//只有一個(gè)參數(shù)的構(gòu)造函數(shù){m_bh = bh;m_name.clear();m_weight = 0;}
};
int main()
{//常規(guī)寫(xiě)法cgril g1(8);//顯示轉(zhuǎn)換cgril g1 = (cgril)8;;//隱式轉(zhuǎn)換cgril g1 = 8;//創(chuàng)建對(duì)象,創(chuàng)建臨時(shí)對(duì)象,再賦值cgril g1;g1 = 8;g1.show();return 0;
}
(2)這個(gè)自動(dòng)類型轉(zhuǎn)換不一定總是好的,我們?nèi)绻幌胧褂米詣?dòng)類型轉(zhuǎn)換,只需要在這個(gè)構(gòu)造函數(shù)的前面添加exolcit關(guān)鍵字,就會(huì)關(guān)閉編譯器的自動(dòng)類型轉(zhuǎn)換功能;
(3)轉(zhuǎn)換函數(shù):這個(gè)函數(shù)就是把這個(gè)類轉(zhuǎn)換為我們的內(nèi)置數(shù)據(jù)類型,例如下面的這個(gè)例子,我們的類里面有string,int double三種數(shù)據(jù)類型,我們使用這個(gè)轉(zhuǎn)換函數(shù)之后就可以進(jìn)行這個(gè)對(duì)應(yīng)的轉(zhuǎn)換:operator 數(shù)據(jù)類型{}就是這個(gè)轉(zhuǎn)換函數(shù)的基本格式;
using namespace std;
class cgril
{
public:int m_bh;string m_name;double m_weight;cgril(){m_bh = 6;m_name = "張三";m_weight = 66.6;}operator int() { return m_bh; }operator double() { return m_weight; }operator string() { return m_name; }
};
int main()
{cgril g;int a = g;cout << "a=" << a << endl;string b = g;cout << "b=" << b << endl;double c = g;cout << "c=" << c << endl;return 0;
}
(4)實(shí)現(xiàn)轉(zhuǎn)換的其他寫(xiě)法:下面的兩種寫(xiě)法也可以達(dá)到相同的效果;
9.繼承
(1)繼承也叫做派生,分為這個(gè)基類和派生類,也叫做父類和子類,表達(dá)的意思都是一樣的,只不過(guò)這個(gè)站的角度不一樣;
?(2)為了更好地了解繼承的相關(guān)語(yǔ)法,我們構(gòu)建下面的這個(gè)場(chǎng)景來(lái)進(jìn)行相關(guān)的介紹:我們首先定義了一個(gè)allcomers類用來(lái)表示的是這個(gè)選秀活動(dòng)參加人員的名字和電話,我們定義的第二個(gè)類表示的就是通過(guò)海選的超女,這個(gè)時(shí)候,我們這個(gè)通過(guò)海選的超女肯定也是需要這個(gè)名字和電話這些基本信息的,我們就可以繼承allcomers類的相關(guān)成員變量,allcomers類就叫做父類,cgril類就叫做子類;
(3)繼承就可以理解為子類可以獲取這個(gè)父類的相關(guān)的成員變量和成員函數(shù),我們實(shí)例里面使用public作為這個(gè)繼承的方式,而且在這個(gè)子類里面我們是可以添加新的成員變量和成員函數(shù)的,如果繼承,父類的成員函數(shù)和成員變量子類都會(huì)有的;
class allcomers
{
public:string m_name;string m_tel;allcomers(){m_name = "某某某";m_tel = "不詳";}void sing(){cout << "我是一只小小鳥(niǎo)" << endl;}void setname(const string& name){m_name = name;}void settel(const string& tel){m_tel = tel;}
};
class cgril:public allcomers
{
public:int m_bh;cgril(){m_bh = 8;}void show(){cout << m_bh << " " << m_name << " " << m_tel << " " << endl;}
};
int main()
{cgril g1;g1.show();return 0;
}
(4)繼承的適用場(chǎng)景:當(dāng)新創(chuàng)建的類和原來(lái)的類有相同的成員變量和成員函數(shù)的時(shí)候,我們就可以使用繼承,或者是類里面有很多的相似的地方的時(shí)候,我們就可以把這個(gè)共性的東西給提取出來(lái),作為一個(gè)子類,這樣就可以簡(jiǎn)化我們的代碼;
例如這個(gè)各種各樣的排序算法,我們都需要輸入數(shù)據(jù),輸出數(shù)據(jù),只不過(guò)就是這個(gè)排序算法的原理不相同罷了,這個(gè)時(shí)候,我們就可以把這個(gè)對(duì)于數(shù)據(jù)處理的部分封裝到一個(gè)子類里面去;