C++_繼承(上)
阿新 • • 發佈:2020-12-29
C++(面向物件)
類和物件
繼承
繼承是面向物件三大特性之一
有些類與類之間存在特殊關係,下級別成員除了擁有上一級的共性,還有自己的特性,這時需要利用繼承的技術,減少重複程式碼。
例:很多網站中,有公共頭部,公共底部,甚至公共的左側列表,只有中心內容不同,接下來分別利用普通寫法和繼承寫法實現網頁內容(黑馬程式設計師網站首頁)。
普通寫法
#include <iostream> using namespace std; //普通寫法 class Java{ public: void Header() { cout<<"黑馬程式設計師"<<endl; } void Footer() { cout<<"相關網站和站內地圖"<<endl; } void Lefter() { cout<<"Java,C++,Python等"<<endl; } void Content() { cout<<"這是Java語言的相關內容"<<endl; } }; class Cpp{ public: void Header() { cout<<"黑馬程式設計師"<<endl; } void Footer() { cout<<"相關網站和站內地圖"<<endl; } void Lefter() { cout<<"Java,C++,Python等"<<endl; } void Content() { cout<<"這是C++語言的相關內容"<<endl; } }; class Python{ public: void Header() { cout<<"黑馬程式設計師"<<endl; } void Footer() { cout<<"相關網站和站內地圖"<<endl; } void Lefter() { cout<<"Java,C++,Python等"<<endl; } void Content() { cout<<"這是Python語言的相關內容"<<endl; } }; void test01() { cout<<"Java的介面為:"<<endl; Java ja; ja.Header(); ja.Lefter(); ja.Content(); ja.Footer(); cout<<"-----------------------"<<endl; cout<<"Cpp的介面為:"<<endl; Cpp cp; cp.Header(); cp.Lefter(); cp.Content(); cp.Footer(); cout<<"-----------------------"<<endl; cout<<"Python的介面為:"<<endl; Python py; py.Header(); py.Lefter(); py.Content(); py.Footer(); } int main() { test01(); return 0; }
繼承寫法
#include <iostream> using namespace std; //繼承寫法 class Base{ //父類 public: void Header() { cout<<"黑馬程式設計師"<<endl; } void Footer() { cout<<"相關網站和站內地圖"<<endl; } void Lefter() { cout<<"Java,C++,Python等"<<endl; } }; //子類 class Java : public Base{ public: void Content() { cout<<"這是Java語言的相關內容"<<endl; } }; class Cpp : public Base{ public: void Content() { cout<<"這是C++語言的相關內容"<<endl; } }; class Python : public Base{ public: void Content() { cout<<"這是Python語言的相關內容"<<endl; } }; void test01() { cout<<"Java的介面為:"<<endl; Java ja; ja.Header(); ja.Lefter(); ja.Content(); ja.Footer(); cout<<"-----------------------"<<endl; cout<<"Cpp的介面為:"<<endl; Cpp cp; cp.Header(); cp.Lefter(); cp.Content(); cp.Footer(); cout<<"-----------------------"<<endl; cout<<"Python的介面為:"<<endl; Python py; py.Header(); py.Lefter(); py.Content(); py.Footer(); } int main() { test01(); return 0; }
同樣的結果
繼承的好處:減少重複程式碼
1.繼承的基本語法
- class 子類 :繼承方式 父類
- 子類也稱派生類,父類也稱基類
- 派生類中的成員,包含兩大部分:一類是從基類繼承過來的,一類是自己增加的成員;從基類繼承過來的表現其共性,而新增的成員體現其個性。
2.繼承方式
- 繼承方式一共有三種:公共繼承(public);保護繼承(protected);私有繼承(private)
- class B :繼承方式 A (B為子類,A為父類)
#include <iostream> using namespace std; //父類 class Base{ public: int m_A; protected: int m_B; private: int m_C; }; //子類 class Son1 : public Base{ //繼承方式為公共型別 public: void func() { m_A = 10; //公共型別 m_B = 10; //保護型別 //m_C = 10; //私有型別,子類無法訪問 } }; class Son2 : protected Base{ //繼承方式為保護型別 public: void func() { m_A = 100; //保護型別 m_B = 100; //保護型別 //m_C = 100; //父類的私有型別,子類無法訪問 } }; class Son3 : private Base{ public: void func() { m_A = 1000; //私有型別 m_B = 1000; //私有型別 //m_C = 1000; //父類的私有型別,子類無法訪問 } }; void test01() { Son1 s1; s1.m_A = 100; //類內的公共型別,類外可以訪問 //s1.m_B = 100; //類內的保護型別,類外不可以訪問 } void test02() { Son2 s2; //s2.m_A = 1000; //類內的保護型別,類外不可以訪問 //s2.m_B = 1000; //類內的保護型別,類外不可以訪問 } void test03() { Son3 s3; //s3.m_A = 10000; //類內的私有型別,類外不可以訪問 //s3.m_B = 10000; //類內的私有型別,類外不可以訪問 } int main() { test01(); test02(); test03(); return 0; }
3.繼承中的物件模型
- 問題:從父類繼承過來的成員,哪些屬於子類物件中?
#include <iostream>
using namespace std;
class Base{
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
class Son : public Base{
public:
int m_D;
};
void test01()
{
Son s;
cout<<sizeof(s)<<endl; //16
}
int main()
{
test01();
return 0;
}
總結:父類中非靜態成員屬性都會被子類繼承下去,父類中的私有成員屬性被編譯器隱藏,因此子類訪問不到,但確實被繼承下去。
注:在Visual Studio中利用開發人員命令提示符可以檢視物件模型,報告單個類佈局。在檔案的目錄下:命令(cl /d1 reportSingleClassLayout類名 “檔名”),例如:
4.繼承中構造和析構的順序
- 子類繼承父類後,當建立子類物件,也會呼叫父類的建構函式
- 問題:父類子類的建構函式和解構函式順序誰先誰後?
#include <iostream>
using namespace std;
class Base{
public:
Base()
{
cout<<"父類的建構函式"<<endl;
}
~Base()
{
cout<<"父類的解構函式"<<endl;
}
};
class Son : public Base{
public:
Son()
{
cout<<"子類的建構函式"<<endl;
}
~Son()
{
cout<<"子類的解構函式"<<endl;
}
};
void test01()
{
Son s; //先構造父類,再構造子類,析構與構造相反
}
int main()
{
test01();
return 0;
}
總結:繼承中,先呼叫父類的建構函式,再呼叫子類的建構函式,解構函式與建構函式相反。