生活随笔
收集整理的這篇文章主要介紹了
【C++grammar】继承与构造
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
目錄 1.繼承 1、Inheritance (繼承) 2、避免一個類被繼承( C++11 ) 3、繼承實例 4、完整代碼 5、繼承的優缺點是什么? 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
{ A ( int i
) { } A ( double d
, int i
) { }
} ; struct B
: A
{ using A
:: A
; int d
{ 0 } ;
} ; int main ( ) { B
b ( 1 ) ;
}
2、調用基類構造函數
若派生類成員也需要初始化,則可以在派生類構造函數中調用基類構造函數。 調用次序: 先調用基類構造函數,再調用內嵌對象構造函數,最后再執行函數體
#include <iostream>
using std
:: cout
;
using std
:: endl
;
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
; }
} ;
class D : public B
{
private : E e1
, e2
;
public : using B
:: B
; D ( ) = default ; 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
;
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
;
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】继承与构造 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。