日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++基础(17)——继承

發布時間:2023/12/20 c/c++ 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++基础(17)——继承 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

1.繼承的概述

1.1概念

1.2繼承的基本用法

?1.3繼承的好處

1.4語法

2.繼承方式

2.1繼承語法

2.2繼承方式

3.繼承中的構造與析構順序

4.繼承同名成員處理方式

4.1繼承同名成員屬性處理方式

?4.2繼承同名成員函數處理方式

?5.同名靜態成員處理

?6.多繼承語法

7.菱形繼承案例

7.1菱形繼承概念


1.繼承的概述

1.1概念

繼承是面向對象三大特性之一。我們發現在定義類的時候,下級別的成員除了擁有上一級別的的共性,還有自己的特性,這時候我們可以考慮使用繼承的技術來減少重復的代碼。

1.2繼承的基本用法

例如我們看到很多的網站中,都有公共的頭部、公共的底部、甚至公共的左側列表,只有中心內容不同,接下來我們分別利用普通寫法和繼承的寫法來實現網頁中的內容,看一下繼承存在的意義以及好處。

#include<iostream> using namespace std;class java {//java網站類 public:void header() {cout << "首頁、公開課、登錄、注冊……(公共頭部)" << endl;}void foter() {cout << "幫助中心、交流合作、站內地圖……(公共底部)" << endl;}void left(){cout << "Java、python、C++……(公共分類列表)" << endl;}void content() {cout << "java學科視頻" << endl;} };//Python頁面 class Python {//java網站類 public:void header() {cout << "首頁、公開課、登錄、注冊……(公共頭部)" << endl;}void foter() {cout << "幫助中心、交流合作、站內地圖……(公共底部)" << endl;}void left() {cout << "Java、python、C++……(公共分類列表)" << endl;}void content() {cout << "Python學科視頻" << endl;} };//C++學習頁面 class Cpp{//java網站類 public:void header() {cout << "首頁、公開課、登錄、注冊……(公共頭部)" << endl;}void foter() {cout << "幫助中心、交流合作、站內地圖……(公共底部)" << endl;}void left() {cout << "Java、python、C++……(公共分類列表)" << endl;}void content() {cout << "C++學科視頻" << endl;} };void test02() {java ja;cout << "java下載視頻頁面如下" << endl;ja.header();ja.foter();ja.left();ja.content();cout << "-----------------------" << endl;cout << "Python下載視頻頁面如下" << endl;Python py;py.header();py.foter();py.left();py.content();cout << "-----------------------" << endl;cout << "C++下載視頻頁面如下" << endl;Cpp cp;cp.header();cp.foter();cp.left();cp.content(); }void main() {test02(); }

可以看到,代碼沒有問題,但是有太多的冗余代碼,這樣看起來太low。所以我們可以考慮使用繼承的方式:

class BasePage {//公共的界面 public:void header() {cout << "首頁、公開課、登錄、注冊……(公共頭部)" << endl;}void foter() {cout << "幫助中心、交流合作、站內地圖……(公共底部)" << endl;}void left() {cout << "Java、python、C++……(公共分類列表)" << endl;} };//Java頁面 class Java :public BasePage {//繼承公共頁面 public:void content() {cout << "Java學科視頻" << endl;} };//Python頁面 class Python :public BasePage {//繼承公共頁面 public:void content() {cout << "Python學科視頻" << endl;} };//C++頁面 class Cpp :public BasePage {//繼承公共頁面 public:void content() {cout << "C++學科視頻" << endl;} };void test02() {Java ja;cout << "java下載視頻頁面如下" << endl;ja.header();ja.foter();ja.left();ja.content();cout << "-----------------------" << endl;cout << "Python下載視頻頁面如下" << endl;Python py;py.header();py.foter();py.left();py.content();cout << "-----------------------" << endl;cout << "C++下載視頻頁面如下" << endl;Cpp cp;cp.header();cp.foter();cp.left();cp.content(); }void main() {test02(); }

?

?1.3繼承的好處

減少重復冗余的代碼

1.4語法

class 子類:繼承方式? 父類 ,如下所示:

?子類:也成為派生類,父類也稱為基類

2.繼承方式

2.1繼承語法

class 子類:繼承方式? 父類?

2.2繼承方式

  • 公共繼承
  • 保護繼承
  • 私有繼承

解析:

  • 子類不能繼承父類的私有屬性
  • 子類如果是公共繼承,在父類中是公共的屬性在子類中同樣是,在父類中是保護繼承的屬性,在子類中也是如此
  • 如果子類是保護繼承,父類中的公共屬性,在子類中變為保護權限,父類保護,子類也是保護
  • 如果子類是私有繼承父類中的公共權限和保護權限屬性,在子類中都變為私有權限
#include<iostream> using namespace std;//公共繼承 class Base1 { public:int m_A; protected:int m_B; private:int m_C; };class Son :public Base1 { public:void func() {m_A = 10;//沒有報錯說明父類中的公共類成員在子類中依然是公共權限m_B = 10;//沒有報錯說明父類中的保護類成員在子類中依然是保護權限//m_C = 10;報錯了,說明父類中的私有屬性,子類拿不到}int m_D; };void test02() {Son s1;s1.m_A = 100;//m_A是公共權限,類內可以訪問,類外也可以訪問//s1.m_B = 100;m_B是保護權限,類內可以訪問,但是類外不可訪問cout << "size of Son =" << sizeof(Son) << endl; }void main() {test02(); }

?

我們也可以利用開發人員命令提示工具查看對象模型(VS自帶的Developer Command Prompt)

  • 查看需要運行的程序在哪個盤,如果在D盤就輸入D:就跳轉到D盤
  • 跳轉文件的路徑:cd? 具體的路徑
  • 查看對象模型輸入:cl /d1 reportSingleClassLayout類名 “文件名”?

如下所示:

3.繼承中的構造與析構順序

子類繼承父類后,當創建子類對象,也會調用父類的構造函數

問題:父類和子類的構造和析構順序誰先誰后呢?

#include<iostream> using namespace std;//繼承中的構造與析構的順序 class Base1 { public:Base1() {cout << "Base1的構造函數" << endl;}~Base1() {cout << "Base1的析構函數" << endl;} };class Son :public Base1 { public:Son() {cout << "Son的構造函數" << endl;}~Son() {cout << "Son的析構函數" << endl;} };void test01() {//Base1 b;Son s;}void main() {test01(); }

可以看出,繼承中的構造與析構順序如下:

先構造父類,再構造子類,析構的順序與構造的順序相反

4.繼承同名成員處理方式

問題:當子類與父類出現同名的成員,如何通過子類對象,訪問到子類或者父類中的同名的數據?

  • 訪問子類同名成員? 直接訪問即可
  • 訪問父類的同名成員需要加作用域

4.1繼承同名成員屬性處理方式

#include<iostream> using namespace std;//繼承中的構造與析構的順序 class Base1 { public:Base1() {m_A = 100;}int m_A ; };class Son :public Base1 { public:Son() {m_A = 200;}int m_A; };void test01() {Son s;cout << "Son m_A=" <<s. m_A << endl;}void main() {test01(); }

可以看出如果直接訪問,m_A是200,說明如果出現同名直接訪問是訪問的自身的成員。

?如果需要拿到父類的成員:

只需要加一個父類的作用域即可訪問到同名中父類的屬性。?

?4.2繼承同名成員函數處理方式

#include<iostream> using namespace std;//繼承中的構造與析構的順序 class Base1 { public:Base1() {m_A = 100;}void func() {cout << "這是base中的函數調用" << endl;}int m_A ; };class Son :public Base1 { public:Son() {m_A = 200;}void func() {cout << "這是son中的函數調用" << endl;}int m_A; };void test01() {Son s;cout << "Son m_A=" <<s. m_A << endl;cout << "Base m_A=" << s.Base1::m_A << endl; }void test02() {Son s;s.func();//當出現重名調用的還是子類的s.Base1::func();//調用父類的成員函數 } void main() {test01();test02(); }

?5.同名靜態成員處理

問題:繼承同名的靜態成員在子類對象上如何進行訪問?

靜態成員和非靜態成員出現同名,處理方式一樣。

  • 訪問子類同名成員,直接訪問即可
  • 訪問父類同名成員,需要加作用域

靜態成員的屬性特點:

  • 編譯階段分配內存
  • 所有對象共享一份數據
  • 類內聲明,類外要初始化
#include<iostream> using namespace std;class Base1 { public:static int m_A ;//類內聲明 }; int Base1::m_A = 100;//類外初始化class Son :public Base1 { public:static int m_A; }; int Son::m_A = 200;void test01() {Son s;cout << "Son m_A=" << s.m_A << endl; } void main() {test01(); }

可以看到直接訪問是訪問的子類的,要想訪問父類需要加一個作用域

?

?訪問可以通過對象訪問,也可以通過類名訪問,如下:

?

#include<iostream> using namespace std;class Base1 { public:static int m_A ;//類內聲明 }; int Base1::m_A = 100;//類外初始化class Son :public Base1 { public:static int m_A; }; int Son::m_A = 200;void test01() {//通過對象訪問Son s;cout << "Son m_A=" << s.m_A << endl;cout << "Base m_A=" << s.Base1::m_A << endl;//通過類名訪問cout << "通過類名訪問:" << endl;cout << "Son 下 m_A=" << Son::m_A<<endl;cout << "Base 下 m_A=" << Son::Base1::m_A << endl; } void main() {test01(); }

繼承靜態的成員屬性以及成員函數的完整代碼如下:

#include<iostream> using namespace std;class Base1 { public:static void func() {cout << "Base static void func()" << endl;}static int m_A ;//類內聲明 }; int Base1::m_A = 100;//類外初始化class Son :public Base1 { public:static void func() {cout << "Son static void func()" << endl;}static int m_A; }; int Son::m_A = 200;void test01() {//通過對象訪問Son s;cout << "Son m_A=" << s.m_A << endl;cout << "Base m_A=" << s.Base1::m_A << endl;//通過類名訪問cout << "通過類名訪問:" << endl;cout << "Son 下 m_A=" << Son::m_A<<endl;cout << "Base 下 m_A=" << Son::Base1::m_A << endl; }void test02() {//通過對象訪問cout << "通過對象訪問" << endl;Son s;s.func();s.Base1::func();//通過類訪問cout << "通過類訪問" << endl;Son::func();Son::Base1::func(); } void main() {test01();cout << "***********************" << endl;test02(); }

?

?6.多繼承語法

C++允許一個類繼承多個類

語法:class 子類 :繼承方式 父類1,繼承方式 父類2 ……

注意:多繼承可能會引發父類中有同名成員的出現,需要加作用域區分

C++在實際開發中不建議使用多繼承

#include<iostream> using namespace std;class Base1 { public:Base1() {m_A = 100;}int m_A; };class Base2 { public:Base2() {m_B = 200;}int m_B; };//子類繼承Base1和Base2 class Son :public Base1,public Base2{ public:Son() {m_C = 300;m_D = 400;}int m_C;int m_D; };void test01() {Son s;cout << "sizeof Son=" << sizeof(s) << endl; }void main() {test01();}

我們可以看看類的結構,具體如何打開的見上一個博客。?

我們可以看出size是16,Son這個類,在Base1中繼承了m_A在Base2中繼承了m_B,自己還有m_C和m_D。

7.菱形繼承案例

7.1菱形繼承概念

  • 兩個派生類繼承同一個基類
  • 又有某個類同時繼承兩個派生類
  • 這種繼承稱為菱形繼承,或者鉆石繼承

例如:羊和駱駝繼承了動物這個類,草泥馬這個動物又繼承了羊和駱駝這個類,若動作有一個m_A這個屬性,那么羊和駱駝也繼承了動物類中的m_A,那么草泥馬這個類就有兩份m_A,而我們只需要一份即可,那怎么辦?

#include<iostream> using namespace std;//動物類 class Animal {int m_Age; };//羊類 class Sheep:public Animal {};//駱駝類 class Camel:public Animal {};//羊駝類(草泥馬類) class SheepCamel :public Sheep, public Camel {};void test01() {SheepCamel sc;sc.m_Age = 10; }void main() {test01();}

test01中直接對m_Age=10賦值會出現“SheepCamel m_Age不明確”的錯誤。所以:當菱形繼承,兩個父類擁有相同的數據,需要加以作用域區分

那么草泥馬(羊駝)的m_Age到底是多少呢,我們只需要一份數據就可以了。我們打出報告可以看到:SheepCamel繼承了兩個類,一個是Sheep一個是Camel,有兩個m_Age,但是我們只需要一個m_Age那么該如何解決呢?

?利用虛繼承可以解決菱形繼承的問題。即為,在繼承之前加一個關鍵字virtual變為虛繼承。

?

#include<iostream> using namespace std;//動物類 class Animal { public:int m_Age; };//利用虛繼承解決菱形繼承問題,繼承之前加上關鍵詞virtual變為虛繼承 //Animal類稱為虛基類 //羊類 class Sheep:virtual public Animal {};//駱駝類 class Camel:virtual public Animal {};//羊駝類(草泥馬類) class SheepCamel :public Sheep, public Camel {};void test01() {SheepCamel sc;sc.Sheep::m_Age = 10;sc.Camel::m_Age = 28;//當菱形繼承,兩個父類擁有相同的數據,需要加以作用域區分cout << "sc.Sheep::m_Age = " << sc.Sheep::m_Age << endl;cout << "sc.Camel::m_Age=" << sc.Camel::m_Age << endl;cout << "SheepCamel m_Age=" << sc.m_Age << endl; }void main() {test01();}

?經過修改后發現年齡都變成28了。我們再看看報告:

可以看到與沒有加關鍵詞virtual時的結構完全不一樣了。可以看到SheepCamel的m_Age只有一份了,而從Sheep和Camel繼承下來的是vbptr。vbptr(virtual base pointer)表示虛基類指針?

總結

以上是生活随笔為你收集整理的C++基础(17)——继承的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。