欧美free性护士vide0shd,老熟女,一区二区三区,久久久久夜夜夜精品国产,久久久久久综合网天天,欧美成人护士h版

首頁綜合 正文
目錄

柚子快報邀請碼778899分享:C++——繼承

柚子快報邀請碼778899分享:C++——繼承

http://yzkb.51969.com/

目錄

引言

繼承的概念和定義

1.繼承的概念

2.繼承的定義

2.1 繼承的語法形式

2.2 繼承中類的叫法

2.3?繼承后的子類成員訪問權(quán)限

基類與派生類的賦值轉(zhuǎn)換

1.派生類對象賦值給基類對象

2.派生類對象的引用賦值給基類對象

3.派生類對象的指針賦值給基類對象

4.基類指針賦值給派生類指針

繼承的作用域

1.同名變量

2.同名函數(shù)

派生類的默認成員函數(shù)

1.對象的構(gòu)造和析構(gòu)遵循特定的順序

2.派生類構(gòu)造函數(shù)調(diào)用基類構(gòu)造函數(shù)

3.析構(gòu)函數(shù)的特殊處理

4.拷貝構(gòu)造與賦值重載必須調(diào)用基類的拷貝構(gòu)造與賦值重載完成對基類的初始化

繼承與友元

繼承與靜態(tài)成員

菱形繼承與虛擬繼承

1.菱形繼承

1.1 單繼承

2.多繼承

3.菱形繼承

2.虛擬繼承

結(jié)束語

引言

C++是一門功能強大的面向?qū)ο缶幊陶Z言,其中繼承是其面向?qū)ο筇匦缘闹匾M成部分。今天我們就來學(xué)習(xí)一下,C++中的繼承這一重要內(nèi)容。

繼承的概念和定義

1.繼承的概念

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

舉個簡單的例子:

比如說一個人,他具有年齡,姓名等個人信息,然后我們可以將這些信息整合為一個Person類,如果說我們還想要定義一個Student的類,這些學(xué)生當然也是人,因此我們可以復(fù)用Person這個類,然后再添加一些其他的信息,例如學(xué)號之類的。

2.繼承的定義

2.1 繼承的語法形式

繼承的定義是通過在子類的聲明中使用基類名,并加上冒號(:)和關(guān)鍵字public(或其他訪問修飾符,如protected或private)來實現(xiàn)的。例如:

class BaseClass

{

// 基類的成員

};

class DerivedClass : public BaseClass // 這里的public可以替換成protected或者private

{

// 子類的成員

};

下面是一個簡單的使用例子:

class Person

{

public:

void Print()

{

cout << _name << endl;

cout << _age << endl;

cout << _height << endl;

}

private:

string _name = "Kana"; //姓名

int _age = 18; //年齡

double _height = 1.50; //身高

};

class Student :public Person

{

private:

int _id = 233333; //學(xué)號

int _grade = 10; //年級

};

可以通過監(jiān)視窗口來看看:

顯然,我們可以看到 Student類 繼承了 Person類 的成員與函數(shù)。

2.2 繼承中類的叫法

(1)子類(或派生類):這是指繼承其他類(即父類)的類。子類可以使用父類的所有非私有屬性和方法,同時也可以添加自己的屬性和方法或重寫父類的方法。

(2)父類(或基類):這是指被其他類(即子類)繼承的類。父類提供了通用的屬性和方法,這些可以被子類繼承和使用。

2.3?繼承后的子類成員訪問權(quán)限

不同的繼承方式產(chǎn)生的繼承效果自然也不一樣。

如下表所示:

類成員/繼承方式public繼承protected繼承private繼承基類的public成員派生類的public成員派生類的protected成員派生類的private成員基類的protected成員派生類的protected成員派生類的protected成員派生類的private成員基類的private成員在派生類中不可見在派生類中不可見在派生類中不可見

1. 基類private成員在派生類中無論以什么方式繼承都是不可見的。這里的不可見是指基類的私有成員還是被繼承到了派生類對象中,但是語法上限制派生類對象不管在類里面還是類外面 都不能去訪問它。

2. 基類private成員在派生類中是不能被訪問,如果基類成員不想在類外直接被訪問,但需要在派生類中能訪問,就定義為protected??梢钥闯霰Wo成員限定符是因繼承才出現(xiàn)的。

3. 實際上面的表格我們進行一下總結(jié)會發(fā)現(xiàn),基類的私有成員在子類都是不可見?;惖钠渌蓡T在子類的訪問方式 == Min(成員在基類的訪問限定符,繼承方式),public > protected > private。

4. 使用關(guān)鍵字class時默認的繼承方式是private,使用struct時默認的繼承方式是public,不過 最好顯示的寫出繼承方式。

5. 在實際運用中一般使用都是public繼承,幾乎很少使用protetced/private繼承,也不提倡使用protetced/private繼承,因為protetced/private繼承下來的成員都只能在派生類的類里面使用,實際中擴展維護性不強。

基類與派生類的賦值轉(zhuǎn)換

在面向?qū)ο缶幊讨校惡团缮愔g的賦值轉(zhuǎn)換涉及到對象的類型兼容性和多態(tài)性。

1.派生類對象賦值給基類對象

派生類對象可以賦值給基類的對象。這里有個形象的說法叫切片或者切割。寓意把派生類中父類那部分切來賦值過去。

相反,基類成員無法賦值給派生類成員,因為有些成員派生類有,而基類沒有。

例如這樣:

class Person

{

public:

Person(string name = "Kana", int age = 18, double height = 1.50):

_name(name),

_age(age),

_height(height)

{

// ...

}

void Print() const

{

cout << _name << endl;

cout << _age << endl;

cout << _height << endl;

}

private:

string _name; // 姓名

int _age; // 年齡

double _height; // 身高

};

class Student : public Person

{

public:

Student(string name = "Kana", int age = 18, double height = 1.50, int id = 233333, int grade = 10)

: Person(name, age, height), _id(id), _grade(grade) {}

void Print() const

{

// 首先調(diào)用基類的 Print 方法

Person::Print();

// 然后打印學(xué)生特有的屬性

cout << "ID: " << _id << endl;

cout << "Grade: " << _grade << endl;

}

private:

int _id; // 學(xué)號

int _grade; // 年級

};

int main()

{

Student s;

s.Print();

// 嘗試將 Student 對象切片為 Person 對象(不推薦,因為會丟失信息)

Person p = s;

p.Print(); // 僅打印 Person 的信息(姓名、年齡、身高)

return 0;

}

輸出結(jié)果為:

2.派生類對象的引用賦值給基類對象

我們可以將一個派生類對象的引用賦值給一個基類類型的引用,而不需要const修飾符。

class Person

{

public:

void Print()

{

cout << "Person Print()" << endl;

}

};

class Student :public Person

{

public:

void Print()

{

cout << "Student Print()" << endl;

}

};

int main()

{

Student s;

Person& p = s;

p.Print();

return 0;

}

輸出結(jié)果為:

3.派生類對象的指針賦值給基類對象

派生類對象的指針可以賦值給基類對象的指針。

class Person

{

public:

void Print() const

{

cout << "Person: Name = " << _name << ", Age = " << _age << endl;

}

Person(string name, int age) : _name(name), _age(age) {}

private:

string _name;

int _age;

};

class Student : public Person

{

public:

void Print() const

{

cout << "Student: ID = " << _id << ", Grade = " << _grade << endl;

}

Student(string name, int age, int id, int grade) : Person(name, age), _id(id), _grade(grade) {}

private:

int _id; // 學(xué)號

int _grade; // 年級

};

int main()

{

Student student("Kana", 18, 12345, 10);

// 將Student對象的指針賦值給Person對象的指針

Person* p = &student;

p->Print();

// 如果要訪問Student特有的成員,需要使用Student類型的指針或引用

Student* s = &student;

s->Print();

return 0;

}

輸出結(jié)果為:

4.基類指針賦值給派生類指針

在C++中,將基類指針直接強制轉(zhuǎn)換為派生類指針是一種危險的做法,通常是不被推薦的,因為它違反了類型安全的原則,并且可能導(dǎo)致未定義行為,包括越界訪問或訪問無效內(nèi)存。

Person p;

Student *s = (Student*) & p; // right

總結(jié):

1.派生類對象可以賦值給 基類的對象 / 基類的指針 / 基類的引用。這里有個形象的說法叫切片或者切割。寓意把派生類中父類那部分切來賦值過去。

2.基類對象不能賦值給派生類對象。

3.基類的指針或者引用可以通過強制類型轉(zhuǎn)換賦值給派生類的指針或者引用。但是必須是基類的指針是指向派生類對象時才是安全的。

繼承的作用域

繼承的作用域決定了從基類繼承到派生類的成員(包括變量和方法)的訪問權(quán)限。

在C++的繼承體系中,基類和派生類各自擁有獨立的作用域。當派生類和基類中定義了同名的成員(無論是變量還是函數(shù)),派生類中的成員會“隱藏”或“重定義”基類中的同名成員。這意味著在派生類的作用域內(nèi),直接訪問該同名成員將引用派生類的成員,而不是基類的成員。

1.同名變量

來看看這段代碼:基類和派生類都有_height這個變量

class Person

{

protected:

string _name = "Kana";

int _age = 18;

double _height = 1.50;

};

class Student :public Person

{

public:

void Print()

{

cout << _name << endl;

cout << _age << endl;

cout << _height << endl;

}

private:

double _height = 1.70;

int _id = 123456;

int _grade = 10;

};

int main()

{

Student s;

s.Print();

return 0;

}

輸出結(jié)果為:

如果想要打印基類中的_height,則需要使用 :: 限定符:

void Print()

{

cout << _name << endl;

cout << _age << endl;

cout << Person::_height << endl;

}

輸出結(jié)果為:

2.同名函數(shù)

如果基類和派生類存在同名函數(shù),會發(fā)生什么呢?

來看看這段代碼:

class A

{

public:

void fun()

{

cout << "fun()" << endl;

}

};

class B : public A

{

public:

void fun(int i)

{

A::fun();

cout << "fun(int i)->" << i << endl;

}

};

int main()

{

B b;

b.fun(1);

};

輸出結(jié)果為:

B 中的 fun 和 A 中的 fun 構(gòu)成隱藏,成員函數(shù)滿足函數(shù)名相同就構(gòu)成隱藏。

由于函數(shù)重載針對的是同一個作用域的函數(shù),而基類與派生類直接作用域不同。因此不是函數(shù)重載。

同樣的,如果需要訪問其他作用域的函數(shù),我們需要使用 :: 操作符:

B b;

b.A::fun(); // 訪問A中的fun函數(shù)

輸出結(jié)果為:

派生類的默認成員函數(shù)

我們知道:在類中有6個默認成員函數(shù),如果不顯示定義,編譯會自動生成。

那么在派生類中,這些成員函數(shù)如何生成?我們來學(xué)習(xí)一下:

1.對象的構(gòu)造和析構(gòu)遵循特定的順序

對象的構(gòu)造和析構(gòu)遵循特定的順序,以確保對象的正確初始化和清理

構(gòu)造函數(shù)調(diào)用順序:

(1)創(chuàng)建派生類對象時,從最頂層的基類開始,逐層向下調(diào)用構(gòu)造函數(shù),直到派生類。

(2)接著,按照派生類中成員變量的聲明順序初始化成員變量(若成員是對象,則調(diào)用其構(gòu)造函數(shù))。

(3)最后,執(zhí)行派生類構(gòu)造函數(shù)體中的代碼。

析構(gòu)函數(shù)調(diào)用順序:

(1)銷毀派生類對象時,首先調(diào)用派生類的析構(gòu)函數(shù)。

(2)然后,按照成員變量聲明的逆序調(diào)用成員變量的析構(gòu)函數(shù)(若成員是對象)。

(3)最后,從最頂層的基類開始,逐層向上調(diào)用析構(gòu)函數(shù),直到派生類的基類。

來看看這個示例:

class Person

{

public:

Person(string name = "Kana")

: _name(name)

{

cout << "Person()" << endl;

}

~Person()

{

cout << "~Person()" << endl;

}

private:

string _name; // 姓名

};

class Student : public Person

{

public:

Student()

{

cout << "Student()" << endl;

}

~Student()

{

cout << "~Student()" << endl;

}

private:

int _id;

};

int main()

{

Student s;

return 0;

}

輸出結(jié)果為:

2.派生類構(gòu)造函數(shù)調(diào)用基類構(gòu)造函數(shù)

(1)派生類的構(gòu)造函數(shù)必須調(diào)用基類的構(gòu)造函數(shù)來初始化基類的成員。

(2)如果基類沒有默認的構(gòu)造函數(shù),則必須在派生類構(gòu)造函數(shù)的初始化列表中顯式調(diào)用基類的一個構(gòu)造函數(shù)。

class Person

{

public:

// Person類的構(gòu)造函數(shù),用于初始化名字

Person(const char* name) :

_name(name)

{

// ...

}

// Person類的拷貝構(gòu)造函數(shù)

Person(const Person& p) :

_name(p._name)

{

}

private:

string _name;

};

class Student : public Person

{

public:

// Student類的構(gòu)造函數(shù),接收學(xué)號和名字

Student(int id, const char* name) :

_id(id),

Person(name)

{

// ...

}

// Student類的默認構(gòu)造函數(shù)

Student() :

Person("Default Student Name"),

_id(0)

{

// ...

}

private:

int _id;

};

3.析構(gòu)函數(shù)的特殊處理

因為后續(xù)一些場景析構(gòu)函數(shù)需要構(gòu)成重寫,重寫的條件之一是函數(shù)名相同。那么編譯器會對析構(gòu)函數(shù)名進行特殊處理,處理成destructor()。

如下所示:

class Person

{

public:

Person(const char* name)

: _name(name)

{

cout << "Person()" << endl;

}

~Person()

{

cout << "~Person()" << endl;

}

private:

string _name;

};

class Student : public Person

{

public:

Student(int num, const char* name)

: _num(num), Person(name)

{

cout << "Student()" << endl;

}

~Student()

{

cout << "~Student()" << endl;

}

private:

int _num;

};

輸出結(jié)果為:

4.拷貝構(gòu)造與賦值重載必須調(diào)用基類的拷貝構(gòu)造與賦值重載完成對基類的初始化

在派生類中實現(xiàn)拷貝構(gòu)造函數(shù)和賦值操作符重載時,需要確保調(diào)用基類的相應(yīng)函數(shù)來完成基類部分的拷貝或賦值操作。

來看個簡單的例子:

class Person

{

public:

// 默認構(gòu)造函數(shù)

Person(const string& name) :

_name(name)

{

// ...

}

// 拷貝構(gòu)造函數(shù)

Person(const Person& p) :

_name(p._name)

{

cout << "Copy Person(" << _name << ")" << endl;

}

// 賦值操作符重載

Person& operator=(const Person& p)

{

if (this != &p)

{

_name = p._name;

cout << "Assign Person(" << _name << ")" << endl;

}

return *this;

}

// 析構(gòu)函數(shù)

~Person()

{

cout << "~Person(" << _name << ")" << endl;

}

string _name;

};

class Student : public Person

{

public:

// 構(gòu)造函數(shù)

Student(int num, const string& name) : Person(name), _num(num) {

cout << "Student(" << _num << ", " << _name << ")" << endl;

}

// 拷貝構(gòu)造函數(shù)

Student(const Student& s) : Person(s), _num(s._num) {

cout << "Copy Student(" << _num << ", " << _name << ")" << endl;

}

// 賦值操作符重載

Student& operator=(const Student& s)

{

if (this != &s)

{

Person::operator=(s); // 調(diào)用基類的賦值操作符

_num = s._num;

}

return *this;

}

// 析構(gòu)函數(shù)

~Student()

{

cout << "~Student(" << _num << ", " << _name << ")" << endl;

}

int _num;

};

繼承與友元

友元關(guān)系不能繼承。友元關(guān)系(friendship)是一種單向的、非傳遞性的關(guān)系,它不能被繼承。這意味著,如果一個類是另一個類的友元,那么這個友元類可以訪問那個類的私有(private)和保護(protected)成員。但是,這種訪問權(quán)限不會延伸到該類的子類。

class Student;//聲明

class Person

{

public:

friend void Display(const Person& p, const Student& s);

protected:

string _name; // 姓名

};

class Student : public Person

{

protected:

int _stuNum; // 學(xué)號

};

void Display(const Person& p, const Student& s)

{

cout << p._name << endl;

cout << s._stuNum << endl;

}

int main()

{

Person p;

Student s;

Display(p, s);

return 0;

}

報錯信息為:

繼承與靜態(tài)成員

基類定義了static靜態(tài)成員,則整個繼承體系里面只有一個這樣的成員。無論派生出多少個子類,都只有一個static成員實例。

來看看這段代碼:

class Person

{

public:

Person()

{

++_count; // 每次創(chuàng)建對象時增加計數(shù)

}

protected:

string _name; // 姓名

public:

static int _count;

};

int Person::_count = 0; // 初始化靜態(tài)成員變量

class Student : public Person

{

protected:

int _stuNum = 0; // 學(xué)號

};

class Graduate : public Student

{

protected:

string _seminarCourse; // 研究科目

};

int main()

{

Student s1;

Student s2;

Student s3;

Graduate s4;

cout << "人數(shù): " << Person::_count << endl;

// 重置計數(shù)

Person::_count = 0;

cout << "人數(shù): " << Person::_count << endl;

return 0;

}

輸出結(jié)果為:

菱形繼承與虛擬繼承

1.菱形繼承

1.1 單繼承

一個子類只有一個直接父類的繼承關(guān)系為單繼承。

2.多繼承

一個子類有兩個或以上直接父類時稱這個繼承關(guān)系為多繼承。

3.菱形繼承

菱形繼承是多繼承的一種特殊情況。

菱形繼承的問題:從下面的對象成員模型構(gòu)造,可以看出菱形繼承有數(shù)據(jù)冗余和二義性的問題。

來看看這段代碼:

class Person

{

public:

string _name; // 姓名

};

class Student : public Person

{

protected:

int _num; //學(xué)號

};

class Teacher : public Person

{

protected:

int _id; // 職工編號

};

class Assistant : public Student, public Teacher

{

protected:

string _majorCourse; // 主修課程

};

int main()

{

Assistant a;

// a._name = "peter"; 這樣會產(chǎn)生二義性無法明確知道訪問的是哪一個類

// 需要顯示指定訪問哪個父類的成員可以解決二義性問題,但是數(shù)據(jù)冗余問題無法解決

a.Student::_name = "xxx";

a.Teacher::_name = "yyy";

return 0;

}

2.虛擬繼承

虛擬繼承可以解決菱形繼承的二義性和數(shù)據(jù)冗余的問題。如上面的繼承關(guān)系,在Student和 Teacher的繼承Person時使用虛擬繼承,即可解決問題。需要注意的是,虛擬繼承不要在其他地方去使用。

像這樣:

class Person

{

public:

string _name; // 姓名

};

//虛繼承

class Student : virtual public Person

{

protected:

int _num; //學(xué)號

};

//虛繼承

class Teacher : virtual public Person

{

protected:

int _id; // 職工編號

};

class Assistant : public Student, public Teacher

{

protected:

string _majorCourse; // 主修課程

};

int main()

{

Assistant a;

a._name = "peter";

return 0;

}

輸出結(jié)果為:

結(jié)束語

假期太擺了,導(dǎo)致寫得太慢了。。。

求點贊收藏評論關(guān)注!?。?/p>

感謝各位大佬的支持?。?!

柚子快報邀請碼778899分享:C++——繼承

http://yzkb.51969.com/

相關(guān)閱讀

評論可見,查看隱藏內(nèi)容

本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。

轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。

本文鏈接:http://gantiao.com.cn/post/19568186.html

發(fā)布評論

您暫未設(shè)置收款碼

請在主題配置——文章設(shè)置里上傳

掃描二維碼手機訪問

文章目錄