国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

C++重溫筆記(四): 繼承和派生

DevWiki / 1625人閱讀

摘要:繼承繼承,就是子類(lèi)繼承父親的特征和行為,使得子類(lèi)具有父類(lèi)的成員變量和方法。此時(shí),被繼承的類(lèi)稱(chēng)為父類(lèi)或基類(lèi),而繼承的類(lèi)稱(chēng)為子類(lèi)或派生類(lèi)。,如果存在繼承關(guān)系的時(shí)候,和就不一樣了基類(lèi)中的成員可以在派生類(lèi)中使用,但是基類(lèi)中的成員不能再派生類(lèi)中使用。

1. 寫(xiě)在前面

c++在線編譯工具,可快速進(jìn)行實(shí)驗(yàn): https://www.dooccn.com/cpp/

這段時(shí)間打算重新把c++撿起來(lái), 實(shí)習(xí)給我的一個(gè)體會(huì)就是算法工程師是去解決實(shí)際問(wèn)題的,所以呢,不能被算法或者工程局限住,應(yīng)時(shí)刻提高解決問(wèn)題的能力,在這個(gè)過(guò)程中,我發(fā)現(xiàn)cpp很重要, 正好這段時(shí)間也在接觸些c++開(kāi)發(fā)相關(guān)的任務(wù),所有想借這個(gè)機(jī)會(huì)把c++重新學(xué)習(xí)一遍。 在推薦領(lǐng)域, 目前我接觸到的算法模型方面主要是基于Python, 而線上的服務(wù)全是c++(算法側(cè), 業(yè)務(wù)那邊基本上用go),我們所謂的模型,也一般是訓(xùn)練好部署上線然后提供接口而已。所以現(xiàn)在也終于知道,為啥只單純熟悉Python不太行了, cpp,才是yyds。

和python一樣, 這個(gè)系列是重溫,依然不會(huì)整理太基礎(chǔ)性的東西,更像是查缺補(bǔ)漏, 不過(guò),c++對(duì)我來(lái)說(shuō), 已經(jīng)5年沒(méi)有用過(guò)了, 這個(gè)缺很大, 也差不多相當(dāng)重學(xué)了, 所以接下來(lái)的時(shí)間, 重溫一遍啦 ?

資料參考主要是C語(yǔ)言中文網(wǎng)光城哥寫(xiě)的C++教程,然后再加自己的理解和編程實(shí)驗(yàn)作為輔助,加深印象。

今天這篇文章是C++非常重要的一塊,關(guān)于類(lèi)的繼承和派生,我們知道C++面向?qū)ο箝_(kāi)發(fā)有四大特性: 抽象,封裝,繼承和多態(tài)。 前面發(fā)現(xiàn),通過(guò)定義類(lèi),把事物的數(shù)據(jù)和功能進(jìn)行抽象,而通過(guò)隱藏對(duì)象的屬性和實(shí)現(xiàn)細(xì)節(jié),對(duì)外只提供接口的方式對(duì)類(lèi)的內(nèi)部成員形成了封裝。 這兩個(gè)前面都已經(jīng)了解過(guò), 而這篇文章主要是整理繼承,即子類(lèi)繼承父類(lèi)的特征和行為,使得子類(lèi)具有父類(lèi)的成員變量和方法, 繼承最大的一個(gè)好處就是代碼復(fù)用,兩個(gè)類(lèi)有一些相同的屬性和方法。

這篇內(nèi)容會(huì)有些偏多,還是各取所需即可 ?

主要內(nèi)容如下:

  • C++繼承和派生初識(shí)
  • C++繼承的三種方式
  • C++繼承時(shí)的名字遮蔽問(wèn)題與作用域嵌套
  • C++繼承時(shí)的對(duì)象內(nèi)存模型
  • C++基類(lèi)和派生類(lèi)的構(gòu)造函數(shù)和析構(gòu)函數(shù)
  • C++的多繼承
  • C++虛繼承(虛基類(lèi),虛繼承構(gòu)造函數(shù),虛繼承內(nèi)存模型)
  • C++向上轉(zhuǎn)型(派生類(lèi)指針賦值給基類(lèi))與過(guò)程原理剖析
  • 借助指針突破訪問(wèn)權(quán)限的限制

Ok, let’s go!

2. C++繼承和派生初識(shí)

2.1 C++面向?qū)ο箝_(kāi)發(fā)的四大特性

在聊C++繼承和派生之前,先來(lái)看看C++面向?qū)ο箝_(kāi)發(fā)的四大特性,這樣能先宏觀把握一下繼承到底位于什么樣的位置。

C++面向?qū)ο箝_(kāi)發(fā)有四大特性: 抽象,封裝,繼承和多態(tài), 正所謂編程語(yǔ)言的背后都非常相似,Java既然也是面向?qū)ο蟮恼Z(yǔ)言,同樣也會(huì)有這四大特性。

抽象和封裝前面其實(shí)已經(jīng)整理過(guò)了, 封裝主要講的是信息隱藏,保護(hù)數(shù)據(jù),而抽象又可以從兩個(gè)層面來(lái)理解。

  • 抽象:
    從現(xiàn)實(shí)生活的具體事物到類(lèi)層面的抽象(包括各個(gè)成員),比如人,有姓名,年齡等各個(gè)屬性,又有學(xué)習(xí),運(yùn)動(dòng)等各項(xiàng)功能,那么就可以定義people類(lèi)把這些數(shù)據(jù)抽象出來(lái),再通過(guò)創(chuàng)建對(duì)象的方式把具體實(shí)體人創(chuàng)建出來(lái),調(diào)用相應(yīng)的方法實(shí)現(xiàn)相應(yīng)的功能。

    宏觀上,這是一種大層面的抽象,而這里面其實(shí)又可以看成數(shù)據(jù)抽象(目標(biāo)的特性信息)和過(guò)程抽象(目標(biāo)的功能是啥,注意不關(guān)注具體實(shí)現(xiàn)邏輯)
  • 封裝
    所謂封裝,就是隱藏對(duì)象的屬性和實(shí)現(xiàn)細(xì)節(jié),僅僅對(duì)外公開(kāi)接口,控制程序?qū)︻?lèi)屬性的讀取和修改。在類(lèi)的內(nèi)部, 成員函數(shù)可以自由修改成員變量,進(jìn)行精確控制,但是在類(lèi)的內(nèi)部,通過(guò)良好的封裝, 減少耦合,隱藏實(shí)現(xiàn)細(xì)節(jié)。
  • 繼承
    繼承,就是子類(lèi)繼承父親的特征和行為,使得子類(lèi)具有父類(lèi)的成員變量和方法。 這個(gè)和生活中兒子繼承他爹的家產(chǎn)差不多是一個(gè)道理,更有意思的是繼承有兩種模式,單繼承和多繼承,單繼承比較好理解,一個(gè)子類(lèi)只繼承一個(gè)父類(lèi), 而多繼承是一個(gè)子類(lèi),繼承多個(gè)父類(lèi),聯(lián)想到生活中,可能有好幾個(gè)爸爸。
  • 多態(tài)
    同一個(gè)行為具有多個(gè)不同表現(xiàn)形式或形態(tài)的能力,有兩種表現(xiàn)形式覆蓋和重載,這個(gè)到這里不理解也不要緊,下一篇文章會(huì)重點(diǎn)整理。
    • 重載: 這個(gè)之前學(xué)習(xí)過(guò),相同作用域中存在多個(gè)同名函數(shù),但函數(shù)的參數(shù)列表會(huì)不一樣
    • 重寫(xiě)或者叫覆蓋: 主要體現(xiàn)在繼承關(guān)系里面,子類(lèi)重寫(xiě)了從他爸那里繼承過(guò)來(lái)的函數(shù),如果子類(lèi)的對(duì)象調(diào)用成員函數(shù)的時(shí)候,如果子類(lèi)的成員函數(shù)重寫(xiě)了他爸的,那么就執(zhí)行子類(lèi)自己的函數(shù),否則繼承他爸的。 這個(gè)也比較好理解,比如同樣是掙錢(qián),他爸的路子很可能和兒子的不一樣,那么兒子在調(diào)用掙錢(qián)的時(shí)候,肯定是先找找兒子有沒(méi)有獨(dú)特的掙錢(qián)方式,如果沒(méi)有,就默認(rèn)和他爸一樣,走他爸的掙錢(qián)方式。

2.2 再看繼承

有了上面的宏觀把握,再看繼承就比較容易理解, 簡(jiǎn)單的講,繼承就是一個(gè)類(lèi)從另一個(gè)類(lèi)獲取成員變量和成員函數(shù)的過(guò)程。 此時(shí),被繼承的類(lèi)稱(chēng)為父類(lèi)或基類(lèi),而繼承的類(lèi)稱(chēng)為子類(lèi)或派生類(lèi)。

C++中派生和繼承是站在不同角度看的同種概念。繼承時(shí)從兒子的角度看,派生是父親的角度看,實(shí)際說(shuō)的是一回事。

派生類(lèi)除了擁有他爹的成員,還可以定義自己的新成員,增強(qiáng)功能,此時(shí)的好處就是只需要定義新成員即可,老的成員和功能,直接繼承,實(shí)現(xiàn)了代碼復(fù)用。

下面是兩種典型使用繼承的場(chǎng)景:

  1. 創(chuàng)建的新類(lèi)與現(xiàn)有類(lèi)相似,只多出若干個(gè)成員變量和成員函數(shù)的時(shí)候,用繼承,減少代碼量,且新類(lèi)會(huì)擁有基類(lèi)的所有功能
  2. 創(chuàng)建多個(gè)類(lèi), 他們擁有很多相似的成員變量或函數(shù),可以用繼承,把這些類(lèi)共同的成員提取出來(lái),定義為基類(lèi),然后從基類(lèi)繼承, 可以減少代碼量,也方便后續(xù)的修改。

繼承的語(yǔ)法:

class 派生類(lèi)名:[繼承方式] 基類(lèi)名{    派生類(lèi)新增加的成員};

直接看個(gè)栗子:

class People{public:    void setname(string name);    string getname();private:    string m_name;    int m_age;};void People::setname(string name){m_name = name;}   string People::getname(){return m_name;}class Student: public People{public:    void setage(int age);    int getage();private:    int m_age;};void Student::setage(int age){m_age = age;}int Student::getage(){return m_age;}int main(){    Student stu;    stu.setname("zhongqiang");    stu.setage(25);    cout << stu.getname() << "的年齡是" << stu.getage() << endl;    return 0;}

這個(gè)例子比較簡(jiǎn)單,不解釋?zhuān)?這里就會(huì)發(fā)現(xiàn), Student繼承了People之后,就有他的setname()getname()方法,在子類(lèi)里面可以直接調(diào)用。

上面演示了public的繼承方式,但繼承方式其實(shí)有3種, public, private, protected, 這哥仨不僅可以修飾類(lèi)的成員,還可以指定繼承方式。如果不寫(xiě),默認(rèn)是private(成員變量和成員函數(shù)默認(rèn)也是private), 那么這三種繼承方式到底有啥區(qū)別呢?

3. C++繼承的三種方式

3.1 哥仨修飾類(lèi)成員

public, private, protected這哥仨,可以修飾類(lèi)成員,之前見(jiàn)識(shí)過(guò)public和private了, 這里加上protected之后統(tǒng)一整理下訪問(wèn)權(quán)限的問(wèn)題。

類(lèi)成員的訪問(wèn)權(quán)限從高到低依次是public --> protected --> private。 public成員可以通過(guò)對(duì)象來(lái)訪問(wèn), private成員不能通過(guò)對(duì)象訪問(wèn), protected成員和private成員蕾西, 也不能通過(guò)對(duì)象訪問(wèn)。

But, 如果存在繼承關(guān)系的時(shí)候, protected和private就不一樣了: 基類(lèi)中的protected成員可以在派生類(lèi)中使用,但是基類(lèi)中的private成員不能再派生類(lèi)中使用

3.2 繼承方式會(huì)影響基類(lèi)成員在派生類(lèi)中的訪問(wèn)權(quán)限

不同的繼承方式使得基類(lèi)成員在派生類(lèi)中的訪問(wèn)權(quán)限也不一樣, 下面這個(gè)很重要:

  • public繼承方式
    • 基類(lèi)中所有public成員 -> 繼承到派生類(lèi) -> public屬性
    • 基類(lèi)中所有protected成員 -> 繼承到派生類(lèi) -> protected 屬性
    • 基類(lèi)中所有private 成員 -> 繼承到派生類(lèi) -> 不能使用
  • protect繼承方式
    • 基類(lèi)中所有public成員 -> 繼承到派生類(lèi) -> protected屬性
    • 基類(lèi)中所有protected成員 -> 繼承到派生類(lèi) -> protected 屬性
    • 基類(lèi)中所有private 成員 -> 繼承到派生類(lèi) -> 不能使用
  • private繼承方式
    • 基類(lèi)中所有public成員 -> 繼承到派生類(lèi) -> private屬性
    • 基類(lèi)中所有protected成員 -> 繼承到派生類(lèi) -> private 屬性
    • 基類(lèi)中所有private 成員 -> 繼承到派生類(lèi) -> 不能使用

使用方法:

  1. 基類(lèi)成員在派生類(lèi)中的訪問(wèn)權(quán)限不得高于繼承方式中指定的權(quán)限,也就是說(shuō)**繼承方式中的public, protected, private是用來(lái)指明基類(lèi)成員在派生類(lèi)中最高訪問(wèn)權(quán)限的。
  2. 不管繼承方式如何, 基類(lèi)中的private成員在派生類(lèi)中始終不能使用(不能在派生類(lèi)的成員函數(shù)中訪問(wèn)或者調(diào)用)
  3. 如果希望基類(lèi)的成員能夠在派生類(lèi)繼承并且使用, 那么這些成員應(yīng)該聲明public或者protected, 只有那些不希望在派生類(lèi)中使用的成員聲明為private
  4. 如果希望基類(lèi)的成員既不向外暴露(不能通過(guò)對(duì)象訪問(wèn)), 還能在派生類(lèi)中使用, 那么就聲明為protected。

下面通過(guò)上面的代碼例子來(lái)演示下, 由于private和protect繼承方式會(huì)改變基類(lèi)成員在派生類(lèi)中的訪問(wèn)權(quán)限,導(dǎo)致繼承關(guān)系復(fù)雜, 所以實(shí)際開(kāi)發(fā)中一般使用public。

把上面的栗子修改下, 測(cè)試下上面的這幾種情況,方便理解,這里只看public繼承下面的。

class People{public:    void setname(string name);    string getname();    void setage(int age);    int getage();    void setsex(string sex);    string getsex();    void setwork(string work);    string getwork();    // 屬性    string m_sex;    protected:    string m_work;    private:    string m_name;    int m_age;};void People::setname(string name){m_name = name;}   string People::getname(){return m_name;}void People::setage(int age){m_age = age;}int People::getage(){return m_age;}void People::setsex(string sex){m_sex=sex;}string People::getsex(){return m_sex;}void People::setwork(string work){m_work=work;}string People::getwork(){return m_work;}class Student: public People{public:        void setscore(float score);    float getscore();        // 定義問(wèn)候方法,這里面會(huì)訪問(wèn)基類(lèi)的私有屬性    string helloname();    string hellowork();    string hellosex();private:    float m_score;};void Student::setscore(float score){m_score = score;}float Student::getscore(){return m_score;}// 訪問(wèn)基類(lèi)中的公有屬性string Student::hellosex(){return "hello, " + m_sex;}// 訪問(wèn)基類(lèi)中的protect屬性string Student::hellowork(){return "hello, " + m_work;}// 訪問(wèn)基類(lèi)中的私有屬性// string Student::helloname(){return "hello, " + m_name;}  error: "std::string People::m_name" is private within this contextint main(){        Student stu;    stu.setname("zhongqiang");    stu.setsex("man");    stu.setwork("student");    stu.setage(25);    stu.setscore(66.6);        cout << stu.getname() << "今年" << stu.getage() << ",性別: " << stu.getsex() << ", 職業(yè): " << stu.getwork() << ", 分?jǐn)?shù): " << stu.getscore() << endl;        //cout << stu.helloname() << endl;    cout << stu.hellowork() << endl;    cout << stu.hellosex() << endl;        // 直接通過(guò)對(duì)象訪問(wèn)屬性    cout << stu.m_sex << endl;     // 公有屬性到子類(lèi)中依然是公有, 可以被訪問(wèn)    //cout << stu.m_name << endl;  // error "std::string People::m_name" is private within this context    //cout << stu.m_work << endl;   // error "std::string People::m_work" is protected within this context        //cout << stu.m_score << endl;  // error "float Student::m_score" is private within this context        return 0;}

在這里面就可以看出來(lái), 在Student里面的成員函數(shù)中,只能訪問(wèn)到他爹的public屬性和protect屬性,不能訪問(wèn)他爹的private屬性。而如果是通過(guò)Student的對(duì)象, 那么只能訪問(wèn)public屬性,protect和private的都訪問(wèn)不到。

在派生類(lèi)中訪問(wèn)基類(lèi)的private成員的唯一方法就是借助基類(lèi)的非private成員函數(shù),如果基類(lèi)沒(méi)有非private成員函數(shù),那么該成員在派生類(lèi)中將無(wú)法訪問(wèn)

這里注意一個(gè)問(wèn)題,這里說(shuō)的是基類(lèi)的 private 成員不能在派生類(lèi)中使用,并不是說(shuō)基類(lèi)的 private 成員不能被繼承。實(shí)際上,基類(lèi)的 private 成員是能夠被繼承的,并且(成員變量)會(huì)占用派生類(lèi)對(duì)象的內(nèi)存,它只是在派生類(lèi)中不可見(jiàn),導(dǎo)致無(wú)法使用罷了。private 成員的這種特性,能夠很好的對(duì)派生類(lèi)隱藏基類(lèi)的實(shí)現(xiàn),以體現(xiàn)面向?qū)ο蟮姆庋b性。

3.3 using改變?cè)L問(wèn)權(quán)限

using關(guān)鍵字可以改變基類(lèi)成員在派生類(lèi)中的訪問(wèn)權(quán)限, 比如將public改成private, protected改成public。

注意:using 只能改變基類(lèi)中 public 和 protected 成員的訪問(wèn)權(quán)限,不能改變 private 成員的訪問(wèn)權(quán)限,因?yàn)榛?lèi)中 private 成員在派生類(lèi)中是不可見(jiàn)的,根本不能使用,所以基類(lèi)中的 private 成員在派生類(lèi)中無(wú)論如何都不能訪問(wèn)

class People{public:    void setname(string name);    string getname();    void setage(int age);    int getage();    void setsex(string sex);    string getsex();    void setwork(string work);    string getwork();    // 屬性    string m_sex;    protected:    string m_work;    private:    string m_name;    int m_age;};void People::setname(string name){m_name = name;}   string People::getname(){return m_name;}void People::setage(int age){m_age = age;}int People::getage(){return m_age;}void People::setsex(string sex){m_sex=sex;}string People::getsex(){return m_sex;}void People::setwork(string work){m_work=work;}string People::getwork(){return m_work;}class Student: public People{public:        void setscore(float score);    float getscore();        // 定義問(wèn)候方法,這里面會(huì)訪問(wèn)基類(lèi)的私有屬性    string helloname();    string hellowork();    string hellosex();        using People::m_work;       // 將m_work提升成public權(quán)限    private:    float m_score;    using People::m_sex;        // 將m_sex降低為private權(quán)限};void Student::setscore(float score){m_score = score;}float Student::getscore(){return m_score;}// 訪問(wèn)基類(lèi)中的公有屬性string Student::hellosex(){return "hello, " + m_sex;}// 訪問(wèn)基類(lèi)中的protect屬性string Student::hellowork(){return "hello, " + m_work;}// 訪問(wèn)基類(lèi)中的私有屬性// string Student::helloname(){return "hello, " + m_name;}  error: "std::string People::m_name" is private within this contextint main(){        Student stu;    stu.setname("zhongqiang");    stu.setsex("man");    stu.setwork("student");    stu.setage(25);    stu.setscore(66.6);        cout << stu.getname() << "今年" << stu.getage() << ",性別: " << stu.getsex() << ", 職業(yè): " << stu.getwork() << ", 分?jǐn)?shù): " << stu.getscore() << endl;       // 直接通過(guò)對(duì)象訪問(wèn)屬性    //cout << stu.m_sex << endl;     // 這個(gè)這時(shí)候就會(huì)報(bào)錯(cuò)了    cout << stu.m_work << endl;   // 這個(gè)就可以訪問(wèn)了    return 0;}

注意,using修改的是派生類(lèi)里面的成員訪問(wèn)權(quán)限。并且是只能修改public和protected的訪問(wèn)權(quán)限。

4. C++繼承時(shí)的名字遮蔽問(wèn)題與作用域嵌套

4.1 名字遮蔽問(wèn)題

這個(gè)說(shuō)的情況是派生類(lèi)中的成員(變量和函數(shù)),如果和基類(lèi)中的成員重名,那么在派生類(lèi)中使用該成員,實(shí)際上用的是派生類(lèi)新增的成員,而不是從基類(lèi)繼承過(guò)來(lái)的。 即派生類(lèi)遮蔽掉從基類(lèi)繼承過(guò)來(lái)的成員。

下面的這個(gè)例子,是Student繼承了People, 又重寫(xiě)了People的show函數(shù),那么通過(guò)Student對(duì)象調(diào)用show的時(shí)候,實(shí)際上是用的Student自身的show函數(shù),但People的show函數(shù)也被Student繼承了過(guò)來(lái),如果想用,需要加上類(lèi)名和域解析符。

class People{public:    void show();protected:    string m_name;    int m_age;};void People::show(){    cout << m_name << " " << m_age << endl; }class Student: public People{public:    Student(string name, int age, string sex);    void show();    // 遮蔽基類(lèi)的show()    private:    string m_sex;};Student::Student(string name, int age, string sex): m_sex(sex){    m_name = name;    m_age = age;    //m_sex = sex;}void Student::show(){    cout << m_name << " " << m_age << " " << m_sex << endl;}int main(){        Student stu("zhongqiang", 25, "man");        // 派生類(lèi)新增的成員函數(shù)    stu.show();        // zhongqiang 25 man        // 使用從基類(lèi)繼承過(guò)來(lái)的成員函數(shù)    stu.People::show();  // zhongqiang 25        return 0;}

這里我在實(shí)驗(yàn)的時(shí)候,發(fā)現(xiàn)個(gè)問(wèn)題,就是Student的構(gòu)造函數(shù)定義的時(shí)候, 本來(lái)是想用構(gòu)造函數(shù)初始化列表的方式,一開(kāi)始寫(xiě)的代碼是這樣:

Student::Student(string name, int age, string sex): m_name(name), m_age(age){    m_sex = sex;}

此時(shí)編譯錯(cuò)誤, 報(bào)錯(cuò)原因class "Student" does not have any field named "m_name", 而如果寫(xiě)成上面那種形式,或者不用參數(shù)化列表的方式,就沒(méi)問(wèn)題, 所以這里我感覺(jué),參數(shù)化列表那個(gè)地方的參數(shù),應(yīng)該是當(dāng)前類(lèi)具有的成員變量才行, 繼承過(guò)來(lái)的應(yīng)該是不能往這里寫(xiě)。

上面的例子,其實(shí)就是派生類(lèi)對(duì)基類(lèi)的函數(shù)重寫(xiě),內(nèi)部在執(zhí)行的時(shí)候, 先找派生類(lèi)里面有沒(méi)有對(duì)應(yīng)的函數(shù),如果有,就先執(zhí)行派生類(lèi)里面的重名函數(shù),如果沒(méi)有,那么再執(zhí)行基類(lèi)里面定義的。

那么,如果派生類(lèi)里面的函數(shù)和基類(lèi)的函數(shù)重名,但形參列表不一樣的時(shí)候,此時(shí)會(huì)發(fā)生重載現(xiàn)象嗎? 答: 不會(huì)。 一旦派生類(lèi)中有同名函數(shù),不管他們的參數(shù)是否一樣,都會(huì)把基類(lèi)中所有的同名函數(shù)遮蔽掉。

這個(gè)就不用例子演示了,而是整理下背后的所以然吧。

4.2 作用域嵌套

之前整理過(guò),每個(gè)類(lèi)都會(huì)有自己的作用域, 在這個(gè)作用域內(nèi)會(huì)定義類(lèi)的成員,那么,當(dāng)存在繼承關(guān)系的時(shí)候, 派生類(lèi)的作用域嵌套在基類(lèi)的作用域之內(nèi),如果一個(gè)名字在派生類(lèi)的作用域沒(méi)有找到,編譯器會(huì)繼續(xù)到外層的基類(lèi)作用域查找該名字的定義。

兩條:

  • 一旦在外層作用域中聲明或定義了某個(gè)名字, 那么它嵌套著的所有內(nèi)層作用域都能訪問(wèn)這個(gè)名字
  • 同時(shí),允許在內(nèi)層作用域重新定義外層作用域中已經(jīng)有的名字

看個(gè)嵌套作用域的例子:

class A{public:    void func();public:    int n = 500;};void A::func(){ cout<<"hello, changjinhu!!!"<<endl; }class B: public A{public:    int n = 5000;    int m;};class C: public B{public:    int n = 50000;    int x;};int main(){    C obj;    cout << obj.n << endl;    obj.func();    cout<<sizeof(C)<<endl;    return 0;}

這個(gè)例子中的繼承關(guān)系, B繼承A, C繼承B,那么作用域的嵌套關(guān)系如下:

  • obj是C類(lèi)的對(duì)象, 訪問(wèn)成員變量n時(shí),由于C類(lèi)自己有n, 那么編譯器就會(huì)直接用,此時(shí)不會(huì)去B或者A中找,即派生類(lèi)中的成員變量會(huì)遮蔽基類(lèi)中的成員變量。
  • 訪問(wèn)成員函數(shù)func()的時(shí)候,編譯器沒(méi)有在C類(lèi)里面找到func這個(gè)名字,會(huì)繼續(xù)到B作用域找,也沒(méi)有找到,再往外,從A里面找到了,于是,調(diào)用A類(lèi)作用域的func()函數(shù)。
  • 對(duì)于成員變量,名字查找過(guò)程好理解,成員函數(shù)要注意,編譯器僅僅是根據(jù)函數(shù)名字查找,不理會(huì)函數(shù)參數(shù),所以一旦在內(nèi)層作用域找到同名函數(shù),不管有幾個(gè),編譯器都不會(huì)再到外層作用域查找,編譯器僅僅把最內(nèi)層作用域的這些同名函數(shù)作為一組候選, 而也只有這組候選構(gòu)成一組重載函數(shù)。 即只有一個(gè)作用域內(nèi)的同名函數(shù)才會(huì)有重載關(guān)系,不同作用域的同名函數(shù)會(huì)造成遮蔽,外層函數(shù)會(huì)被內(nèi)層遮蔽掉, 這其實(shí)也是重載和重寫(xiě)的一個(gè)區(qū)別了。

有了上面這些,就能回答上面的兩點(diǎn)疑問(wèn):

  1. 構(gòu)造函數(shù)的參數(shù)初始化列表那里, 初始化列表里面要列本類(lèi)作用域里面的成員,如果是外層作用域,會(huì)報(bào)錯(cuò)找不到成員
  2. 派生類(lèi)和基類(lèi)擁有不同的作用域,所以它們的同名函數(shù)不具有重載關(guān)系, 而是重寫(xiě)或者覆蓋。

5. C++繼承時(shí)的對(duì)象內(nèi)存模型

沒(méi)有繼承時(shí)對(duì)象內(nèi)存的分布情況,成員變量和成員函數(shù)分開(kāi)存儲(chǔ):

  • 對(duì)象的內(nèi)存中只包含成員變量,存儲(chǔ)在棧區(qū)或者堆區(qū)(new創(chuàng)建)
  • 成員函數(shù)與對(duì)象內(nèi)存分離,存儲(chǔ)在代碼區(qū)

有繼承關(guān)系的時(shí)候, 派生類(lèi)的內(nèi)存模型可以看成是基類(lèi)成員變量和新增成員變量的總和,所有成員函數(shù)仍然存儲(chǔ)在另外一個(gè)區(qū)域–代碼區(qū),由所有對(duì)象共享。

看個(gè)例子:

class A{public:    A(int a, int b);protected:    int m_a;    int m_b;};A::A(int a, int b): m_a(a), m_b(b){}class B
            
                     
             
               

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/122560.html

相關(guān)文章

  • Java學(xué)習(xí)筆記1-開(kāi)發(fā)環(huán)境安裝

    摘要:注意在完成配置環(huán)境變量后測(cè)試是否安裝成功時(shí)鍵入命令安裝出現(xiàn)了這樣的問(wèn)題,需要升級(jí)具體安裝方法,可以參考該文檔教程下載最新的之后,上邊的問(wèn)題就解決了。 由于其他項(xiàng)目中要使用Java的項(xiàng)目,所以,簡(jiǎn)單的學(xué)下,好對(duì)項(xiàng)目有個(gè)大概的了解。 一、Eclipse 安裝 1.下載地址為: https://www.eclipse.org/downl... 2.配置環(huán)境 在配置環(huán)境變量中:設(shè)置JAVA_H...

    SimpleTriangle 評(píng)論0 收藏0
  • C++繼承

    摘要:基類(lèi)中的構(gòu)造函數(shù)和析構(gòu)函數(shù)不能被繼承,在派生類(lèi)中需要定義新的構(gòu)造函數(shù)和析構(gòu)函數(shù),私有成員不能被繼承。對(duì)象訪問(wèn)在派生類(lèi)外部,通過(guò)派生類(lèi)的對(duì)象對(duì)從基類(lèi)繼承來(lái)的成員的訪問(wèn)。 ...

    不知名網(wǎng)友 評(píng)論0 收藏0
  • C++繼承

    摘要:例如,在關(guān)鍵字為的派生類(lèi)當(dāng)中,所繼承的基類(lèi)成員的訪問(wèn)方式變?yōu)椤@^承中的作用域在繼承體系中的基類(lèi)和派生類(lèi)都有獨(dú)立的作用域。為了避免類(lèi)似問(wèn)題,實(shí)際在繼承體系當(dāng)中最好不要定義同名的成員。 ...

    URLOS 評(píng)論0 收藏0
  • Python 3 學(xué)習(xí)筆記之——面向?qū)ο?/b>

    摘要:類(lèi)的介紹類(lèi)用來(lái)描述具有相同的屬性和方法的對(duì)象的集合。類(lèi)變量類(lèi)變量在整個(gè)實(shí)例化的對(duì)象中是公用的。類(lèi)的定義語(yǔ)法格式如下類(lèi)有一個(gè)名為的特殊方法,也即是構(gòu)造函數(shù),該方法會(huì)在定義對(duì)象的時(shí)候自動(dòng)調(diào)用,可以通過(guò)參數(shù)傳遞來(lái)對(duì)類(lèi)的實(shí)例進(jìn)行設(shè)定。 1. 類(lèi)的介紹 類(lèi)(Class) 用來(lái)描述具有相同的屬性和方法的對(duì)象的集合。它定義了該集合中每個(gè)對(duì)象所共有的屬性和方法。對(duì)象是類(lèi)的實(shí)例,類(lèi)是對(duì)象的抽象。 ...

    yzzz 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<