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

歡迎訪問 生活随笔!

生活随笔

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

c/c++

【C++grammar】继承与构造

發布時間:2023/12/1 c/c++ 56 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【C++grammar】继承与构造 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

  • 1.繼承
    • 1、Inheritance (繼承)
    • 2、避免一個類被繼承( C++11 )
    • 3、繼承實例
    • 4、完整代碼
    • 5、繼承的優缺點是什么?
  • 2.繼承中的構造函數
    • 1、 派生類繼承的成員
    • 2、調用基類構造函數
  • 3.繼承中的默認構造函數
    • 1、基類的無參構造函數
    • 2、由編譯器自動生成的基類構造函數會不會被派生類繼承?
  • 4. 構造鏈和析構鏈
    • 1、構造函數鏈
    • 2、析構函數鏈
    • 3、例1
    • 4、例2
    • 5、調用所有的構造函數和析構函數

1.繼承

1、Inheritance (繼承)


2、避免一個類被繼承( C++11 )

class B final {}; class D : public B {};

編譯后的輸出是 (Visual Studio)
error C3246: “D”: 無法從“B”繼承,因為它已被聲明為“final”這是程序輸出

3、繼承實例

1、創建rectangle類、Circle類,從shape類繼承。

class Rectangle : public Shape {......}; class Circle: public Shape {......};

2、使用基類的構造函數初始化基類的數據成員
繼承之后,rectangle也獲得了shape的屬性和方法,這里修改rectangle類的有參初始化函數,同時也對繼承過來的基類數據成員進行初始化。

Circle::Circle(double radius_, Color color_, bool filled_) : Shape{color_,filled_} {radius = radius_; } Rectangle::Rectangle(double w, double h, Color color_, bool filled_) :width{ w }, height{h}, Shape{ color_,filled_ } {}

4、完整代碼

繼承與構造test1代碼附錄

5、繼承的優缺點是什么?

繼承方便程序員使用他人寫好的類來實現自己的功能,而不用重復造輪子。
壞處是有時繼承過程中會繼承到許多無用的信息,而且增加了程序的復雜性,容易出錯。

2.繼承中的構造函數

1、 派生類繼承的成員

C++11:派生類不繼承的特殊函數:

(1) 析構函數
(2) 友元函數

繼承基類構造函數:

(1) using A::A; 繼承所有基類ctor
(2) 不能僅繼承指定的某個基類ctor

調用繼承的構造函數

struct A { // 等價于 class A { public:A(int i) {}A(double d, int i) {}// ... };struct B : A { // C++11using A::A; // 繼承基類所有構造函數int d{ 0 }; // 就地初始化 };int main() {B b(1); // 調A(int i) }

2、調用基類構造函數

若派生類成員也需要初始化,則可以在派生類構造函數中調用基類構造函數。
調用次序:
先調用基類構造函數,再調用內嵌對象構造函數,最后再執行函數體

#include<iostream> using std::cout; using std::endl;//task1:繼承構造函數 //創建基類B及構造函數B(int),B(char)和派生類D; //D中不繼承/繼承B的ctor時的效果。//task2:派生類中調用基類構造函數 //D中增加成員double x;及D(double),在D(double)初始化列表調用B(i)并初始化x//task3:派生類先調用基類ctor,再構造內嵌對象 //增加類E及E(int) ,并在D中加入E的兩個對象;創建D對象觀察E ctor和B ctor 次序class B { public:B() { cout << "B()" << endl; }B(int i) { cout << "B("<< i << ")" << endl; }B(char c) { cout << "B(" << c << ")" << endl; } }; class E { public:E() { cout << "E()" << endl; } };//D里面沒有構造函數,所以編譯器會自動生成一個默認構造函數,去調用基類的默認構造函數 class D :public B { private://double x{ 0.0 };E e1, e2; public://繼承構造函數using B::B;D() = default; //顯示聲明//D(int i):B(i){}//D(char c):B(c){}//先調用基類構造函數,再調用內嵌對象構造函數,最后再執行函數體D(double x) :e1{}, e2{}, B(static_cast<int>(x)){ cout << "D(" << x << ")" << endl;} };int main() {B b;D d;D d2{3.02}; }

當程序員在派生類構造函數中顯式調用基類構造函數時,應將被調用基類構造函數放在派生類構造函數初始化列表中。

3.繼承中的默認構造函數

1、基類的無參構造函數

若基類ctor未被顯式調用,基類的默認構造函數就會被調用。
所以這種繼承的,一定要小心地書寫基類的默認構造函數。

2、由編譯器自動生成的基類構造函數會不會被派生類繼承?

class A {}; class B: public A { public:using A::A; }

編譯器為基類生成的默認構造函數會不會被繼承到類B中?
在B中提供有參構造函數使編譯器不生成默認構造函數,這段代碼可以執行成功。所以在沒有其他機制的情況下,暫且認為編譯器生成的A類默認構造函數被B類繼承了。
C++編譯器生成默認的構造函數的幾種情況

4. 構造鏈和析構鏈

1、構造函數鏈

構造類實例會沿著繼承鏈調用所有的基類ctor。
調用次序: base first, derive next (父先子后)。

2、析構函數鏈

dtor與ctor正好相反。
調用次序: derive first, base next (子先父后)

3、例1

任務1:創建類結構:Computer->PC->Desktop/Laptop以及相應的ctor/dtor
main中創建Desktop/Laptop的對象,觀察ctor/dtor調用次序

#include <iostream> using std::cout; using std::endl;//任務1:創建類結構:Computer->PC->Desktop/Laptop以及相應的ctor/dtor // main中創建Desktop/Laptop的對象,觀察ctor/dtor調用次序 class Computer { public:Computer() { cout << "Computer()" << endl; }~Computer() { cout << "~Computer()" << endl; } }; class PC : public Computer { public:PC() { cout << "PC()" << endl; }~PC() { cout << "~PC()" << endl; } };class Desktop : public PC { public:Desktop() { cout << "Desktop()" << endl; }~Desktop() { cout << "~Desktop()" << endl; } };class Laptop : public PC { public:Laptop() { cout << "Laptop()" << endl; }~Laptop() { cout << "~Laptop()" << endl; } }; int main() {Desktop d();Laptop l();return 0; }

效果:

4、例2

任務2:增加類Camera作為Laptop的內嵌對象c的類型
main中創建Laptop對象,觀察內嵌對象c的構造與基類構造次序

#include <iostream> using std::cout; using std::endl; //任務2:增加類Camera作為Laptop的內嵌對象c的類型 // main中創建Laptop對象,觀察內嵌對象c的構造與基類構造次序class Computer { public:Computer() { cout << "Computer()" << endl; }~Computer() { cout << "~Computer()" << endl; } }; class PC : public Computer { public:PC() { cout << "PC()" << endl; }~PC() { cout << "~PC()" << endl; } };class Desktop : public PC { public:Desktop() { cout << "Desktop()" << endl; }~Desktop() { cout << "~Desktop()" << endl; } }; class Camera { public:Camera() { cout << "Camera()" << endl; }~Camera() { cout << "~Camera()" << endl; } }; class Laptop : public PC { private:Camera c{}; public:Laptop() { cout << "Laptop()" << endl; }~Laptop() { cout << "~Laptop()" << endl; } }; int main() {Desktop d{};Laptop l{};return 0; }

效果:

構造過程:在祖先類的構造函數執行完后,執行內嵌對象的構造函數,最后執行自己的構造函數。
析構過程:與繼承鏈相反。

5、調用所有的構造函數和析構函數

我們知道,一個類可能有不止一個構造函數。
那么,能否寫出一個例子,創建一個派生類對象,從而把單繼承鏈(鏈無分支)上的所有類的所有構造函數和析構函數都調一遍?
使用代理構造:【C++grammar】代理構造、不可變對象、靜態成員

#include <iostream> using std::cout; using std::endl; class A { public:A() : A(0) { cout << "A()" << endl; }A(int i) : A(i, 0) { cout << "A(int i)" << endl; }A(int i, int j) {num1 = i;num2 = j;average = (num1 + num2) / 2;cout << "A(int i, int j)" << endl;} private:int num1;int num2;int average; }; class A_child : public A { public:A_child() { cout << "A_child()" << endl; }~A_child() { cout << "~A_child()" << endl; } }; int main() {A_child l{};return 0; }

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的【C++grammar】继承与构造的全部內容,希望文章能夠幫你解決所遇到的問題。

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