日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學(xué)無(wú)先后,達(dá)者為師

網(wǎng)站首頁(yè) 編程語(yǔ)言 正文

一文搞懂C++中繼承的概念與使用_C 語(yǔ)言

作者:。菀枯。 ? 更新時(shí)間: 2022-09-15 編程語(yǔ)言

前言

我們都知道面向?qū)ο笳Z(yǔ)言的三大特點(diǎn)是:**封裝,繼承,多態(tài)。**之前在類(lèi)和對(duì)象部分,我們提到了C++中的封裝,那么今天呢,我們來(lái)學(xué)習(xí)一下C++中的繼承。

繼承概念及定義

繼承概念

繼承(inheritance)機(jī)制是面向?qū)ο蟪绦蛟O(shè)計(jì)使代碼可以復(fù)用的最重要的手段,它允許程序員在保持原有類(lèi)特性的基礎(chǔ)上進(jìn)行擴(kuò)展,增加功能,這樣產(chǎn)生新的類(lèi),稱(chēng)派生類(lèi)。繼承呈現(xiàn)了面向?qū)ο蟪绦蛟O(shè)計(jì)的層次結(jié)構(gòu),體現(xiàn)了由簡(jiǎn)單到復(fù)雜的認(rèn)知過(guò)程。以前我們接觸的復(fù)用都是函數(shù)復(fù)用,繼承是類(lèi)設(shè)計(jì)層次的復(fù)用

看概念是一件很讓人疑惑的東西,接下來(lái)我就來(lái)舉個(gè)例子來(lái)看看繼承具體是什么東西

首先我們定義兩個(gè)類(lèi),一個(gè)Student類(lèi),一個(gè)Teacher類(lèi),二者都有年齡和姓名,學(xué)生有學(xué)號(hào),老師有工號(hào)。

class Student
{
private:
    int _age;     //年齡
    string _name; //姓名
    int _stuid;   //學(xué)號(hào)
};

class Teacher
{
private:
    int _age;     //年齡
    string _name; //姓名
    int _jobid;   //工號(hào)
};

我們發(fā)現(xiàn)這兩個(gè)類(lèi)有一些重復(fù)的地方,比如年齡和姓名,這二者是他們的成員,此時(shí)代碼就產(chǎn)生了冗余。那么我們可不可以像個(gè)方法去復(fù)用這兩個(gè)成員呢?繼承此時(shí)就可以發(fā)揮它的重大作用。

我們將他們重復(fù)的地方提取出來(lái),重新定義一個(gè)Person類(lèi)。而Student類(lèi)和Teacher類(lèi)將Person類(lèi)繼承下來(lái),此時(shí)我們就實(shí)現(xiàn)了代碼的復(fù)用。

class Person
{
protected:
	int _age;     //年齡
	string _name; //姓名
};

class Student : public Person
{
private:
	int _stuid; //學(xué)號(hào)
};

class Teacher : public Person
{
private:
	int _jobid; //工號(hào)
};

我們首先分別用Student和Teacher類(lèi)來(lái)創(chuàng)建兩個(gè)對(duì)象,來(lái)看看對(duì)象里面有什么。

int main()
{
    Teacher t;
    Student s;
    return 0;
}

此時(shí)我們可以看到我們創(chuàng)建的兩個(gè)對(duì)象里面都含有從Person類(lèi)中繼承過(guò)來(lái)的 age 和 name 兩個(gè)成員。

所以繼承實(shí)際上是一個(gè)代碼的復(fù)用,我們可以借用已完成的類(lèi)的代碼來(lái)完善我們需要?jiǎng)?chuàng)造的新類(lèi)。

繼承定義

以我們剛剛創(chuàng)建的Student類(lèi)來(lái)舉例:我們看到Person是父類(lèi),也稱(chēng)作基類(lèi)。Student是子類(lèi),也稱(chēng)作派生類(lèi)。

繼承方式

我們?cè)陬?lèi)和對(duì)象的時(shí)候介紹了三種訪問(wèn)限定符:public(公有),protected(保護(hù))和private(私有)。訪問(wèn)限定符限定了我們?cè)陬?lèi)外如何去訪問(wèn)類(lèi)中的成員。

在繼承中我們一樣使用這三種限定符來(lái)限定子類(lèi)該如何去訪問(wèn)父類(lèi)的的成員,下面有一張表來(lái)表示他們的關(guān)系。

類(lèi)成員\繼承方式 public繼承 protected繼承 private繼承
父類(lèi)的public成員 派生類(lèi)的public成員 派生類(lèi)的protected成員 派生類(lèi)的private成員
父類(lèi)的protected成員 派生類(lèi)的protected成員 派生類(lèi)的protected成員 派生類(lèi)的private成員
父類(lèi)的private成員 在派生類(lèi)中不可見(jiàn) 在派生類(lèi)中不可見(jiàn) 在派生類(lèi)中不可見(jiàn)

首先解釋一下在派生類(lèi)中不可見(jiàn)是什么意思,就如同我們?cè)陬?lèi)外無(wú)法直接去修改類(lèi)中的private成員一樣,我們?cè)谧宇?lèi)中也無(wú)法直接修改父類(lèi)的private成員。

如何簡(jiǎn)潔的去記這個(gè)表呢?在C++中權(quán)限的關(guān)系:public > protected > private。在繼承的時(shí)候呢,父類(lèi)成員的權(quán)限取的是:父類(lèi)成員原本權(quán)限和繼承方式中較小的那個(gè)。

比如父類(lèi)的A成員原本權(quán)限為public,而子類(lèi)的繼承方式為private。此時(shí)A成員相對(duì)子類(lèi)來(lái)說(shuō)就為private成員

父類(lèi)和子類(lèi)對(duì)象賦值轉(zhuǎn)換

子類(lèi)的對(duì)象可以賦值給 父類(lèi)的對(duì)象/父類(lèi)的指針/父類(lèi)的應(yīng)用,那么是如何進(jìn)行賦值的呢?形象一點(diǎn)來(lái)說(shuō)就是切片,將子類(lèi)中父類(lèi)的部分切割父類(lèi)。

但我們無(wú)法反過(guò)來(lái),將父類(lèi)對(duì)象賦值給子類(lèi)對(duì)象。

繼承中的作用域

在繼承體系中父類(lèi)和子類(lèi)都有獨(dú)立的作用域,如果子類(lèi)和父類(lèi)中有同名的成員,子類(lèi)成員將屏蔽對(duì)父類(lèi)成員的直接訪問(wèn),這種情況叫隱藏,也叫重定義。

下面還是用我們的Person類(lèi)和Student類(lèi)來(lái)舉個(gè)栗子,我們分別在Person類(lèi)和Student類(lèi)中加入一個(gè)print函數(shù),通過(guò)打印內(nèi)容來(lái)區(qū)分調(diào)用的為哪一print函數(shù)。

class Person
{
protected:
    int _age;
    string _name;

public:
    void print()
    {
        cout << "Person"<< endl;
    }
};

class Student : public Person
{
private:
    int _stuid; //學(xué)號(hào)
    public:
    void print()
    {
        cout << "Student" << endl;
    }
};

接下來(lái)我們創(chuàng)建一個(gè)對(duì)象然后來(lái)試一下結(jié)果。

int main()
{
    Student s;
    s.print();
    return 0;
}

我們可以看到我們調(diào)用的為Student中的print函數(shù)。此時(shí)子類(lèi)的print函數(shù)已經(jīng)對(duì)父類(lèi)的print函數(shù)進(jìn)行了重定義。重定義不代表子類(lèi)無(wú)法去調(diào)用父類(lèi)的同名函數(shù),只是不那么直接而已。使用下面這種方法我們就可以調(diào)用父類(lèi)中的同名函數(shù)。

int main()
{
    Student s;
    s.Person::print();
    return 0;
}

通過(guò)指定類(lèi)域,我們就可以去調(diào)用父類(lèi)的print函數(shù)。但在實(shí)際中最好不要去定義同名函數(shù)以免帶來(lái)問(wèn)題。

派生類(lèi)的默認(rèn)成員函數(shù)

首先我們來(lái)回顧一下有哪幾個(gè)默認(rèn)成員函數(shù)。

那么在子類(lèi)中,這些默認(rèn)成員函數(shù)是怎么生成的呢?

1.子類(lèi)的構(gòu)造函數(shù)必須調(diào)用父類(lèi)的構(gòu)造函數(shù)初始化父類(lèi)的那一部分成員。如果父類(lèi)沒(méi)有默認(rèn)的構(gòu)造函數(shù),則必須在派生類(lèi)構(gòu)造函數(shù)的初始化列表中顯式調(diào)用。還是用我們的Person類(lèi)和Student類(lèi)舉例。

情況一:有默認(rèn)構(gòu)造函數(shù)

class Person
{
protected:
    int _age;
    string _name;

public:
    Person()
    {
        cout << "Person" << endl; //調(diào)用就打印
    }
};

class Student : public Person
{
private:
    int _stuid; //學(xué)號(hào)
public:
    Student()
    {
        cout << "Student" << endl; //調(diào)用就打印
    }
};

int main()
{
    Student s;
    return 0;
}

情況二:無(wú)默認(rèn)構(gòu)造函數(shù)

class Person
{
protected:
    int _age;
    string _name;

public:
    Person(int age, string name)
    {
        cout << "Person" << endl;
    }
};

class Student : public Person
{
private:
    int _stuid; //學(xué)號(hào)
public:
    Student()
        : Person(19, "wanku") //無(wú)默認(rèn)構(gòu)造,此時(shí)我們需要在初始化列表中初始化
    {
        cout << "Student" << endl;
    }
};

int main()
{
    Student s;
    return 0;
}

int main()
{
    Student s;
    return 0;
}

2.子類(lèi)的拷貝構(gòu)造函數(shù)必須調(diào)用父類(lèi)的拷貝構(gòu)造完成父類(lèi)的拷貝初始化化。

class Person
{
protected:
    int _age;
    string _name;

public:
    Person(int age = 10, string name = "wanku")
    {
        cout << "Person" << endl;
    }

    Person(const Person &p)
        : _age(p._age), _name(p._name)
    {}
};

class Student : public Person
{
private:
    int _stuid; //學(xué)號(hào)
public:
    Student()
    {
        cout << "Student" << endl;
    }

    Student(const Student &s)
        : Person(s) /*顯示調(diào)用父類(lèi)的拷貝構(gòu)造*/, _stuid(s._stuid)
    {}
};

有些朋友可能會(huì)疑惑,在Person類(lèi)中的拷貝構(gòu)造函數(shù)參數(shù)明明是Person類(lèi),為什么我們的Student類(lèi)可以傳過(guò)去呢?那是因?yàn)槲覀儎倓傊v的切片原理,當(dāng)我們把子類(lèi)對(duì)象傳過(guò)去時(shí),編譯器會(huì)進(jìn)行切分,然后再傳給父類(lèi)。

3.派生類(lèi)的operator=必須要調(diào)用基類(lèi)的operator=完成基類(lèi)的復(fù)制。(原理和拷貝構(gòu)造大體相似,值得注意的是:當(dāng)我們?cè)谧宇?lèi)直接想去調(diào)用父類(lèi)的operator= 時(shí),會(huì)發(fā)生重定義,使用時(shí)記得加上父類(lèi)的作用域)

4.在繼承中一個(gè)對(duì)象的歷程如下:父類(lèi)的構(gòu)造函數(shù) –> 子類(lèi)的構(gòu)造函數(shù) –> 子類(lèi)的析構(gòu)函數(shù) –> 父類(lèi)的析構(gòu)函數(shù)。這個(gè)過(guò)程相當(dāng)于把這些行為存在一個(gè)棧中,然后再把行為從棧中拿出來(lái)一般

派生類(lèi)的友元與靜態(tài)成員

父類(lèi)的友元不是子類(lèi)的友元。(你爸爸的朋友不一定是你的朋友)

父類(lèi)中有一個(gè)靜態(tài)成員,那么子類(lèi)和父類(lèi)共用一個(gè)靜態(tài)成員。(靜態(tài)成員并不存在對(duì)象中,只開(kāi)辟一個(gè)空間,所以只能共用一個(gè))

繼承關(guān)系

單繼承

一個(gè)子類(lèi)只有一個(gè)直接父類(lèi)。

多繼承

一個(gè)子類(lèi)有兩個(gè)及以上的父類(lèi)

菱形繼承

多繼承的一種特殊情況

原文鏈接:https://blog.csdn.net/m0_60447315/article/details/125909713

欄目分類(lèi)
最近更新