你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

C++——继承中的构造和析构

[复制链接]
gaosmile 发布时间:2020-8-21 10:03
在我们前面学习过类中的构造函数,以及析构函数,那么自然而然,在继承关系中,必然是存在着析构和构造着。
一、子类对象的构造
1、问题的引出
如何初始化父类成员?
父类构造函数和子类构造函数有什么关系?
2、子类中的构造函数怎样初始化父类成员:
  • 子类中也是可以定义构造函数的:
    ) c$ Y' L; p3 Y# W4 F% o
--必须对继承而来的成员进行初始化,那么怎样初始化呢?这里有两种方式:
-直接通过初始化列表或者赋值的方式进行初始化
-调用父类构造函数进行初始化
3、父类构造函数在子类中的调用方式
  • 默认调用
    / v2 t# h0 d4 i+ w* d
-适用于无参构造函数和使用默认参数的构造函数
  • 显示调用
    1 k) L: N" B( A* Q. O
-通过初始化列表进行调用
-适用于所有父类构造函数
实践代码模板:
class Child :public Parent
- U) u4 i5 F! j' d% q1 K{! ~  a$ Q* g  o. ^7 ~8 K
  public:( Q9 c3 y; x* W5 H% Y
     Child()//隐式调用
' A5 O  M& I4 _4 E     {
3 q* g: \" a) e/ H* }        cout<< "Child()" <<endl;0 b! j5 k& }" \9 v* n7 J- f/ }
     }
) W: H4 P# ~( D( Z! U     Child(string s)
+ E2 N( w9 d6 g# A% g  :Parent("Parent to Parent")3 a5 n0 \: t6 i5 A
  {
1 _7 Q5 o* M, A" K/ o     cout<<"Child()"<<s<<endl;
' T% |) b- c  f) o) h, ^  }
3 `) {& T9 f0 ?};  F2 d- ]9 c, ?8 V6 F: I; |
代码实践:
#include <iostream>
7 |( _; i  \7 G* I6 i#include <string>
" r$ L/ r% |5 F
6 {7 n7 _- P( I4 T# V1 b& p! |* }using namespace std;, T* {  q7 W' \1 w+ v6 |: q

! O! s* ~  G% n8 a- Xclass Parent
) a* D/ G: w0 f+ I6 `+ f{: Z7 [( H" @2 H& w2 j
public:
* r8 N9 H5 O+ r6 k; d( k4 P    Parent()/ \2 [+ D9 v- R4 ?# g" ]/ t" t
    {
+ ~; k) L: J2 u$ y8 g  w        cout << "Parent()" << endl;
# J  A9 O6 S) Q# \3 e8 p    }+ V. E# j, |) f% f7 E6 O4 l
    Parent(string s)
" m1 l8 G  O+ ]* G  B    {* d- I4 M# C; B6 D. R
        cout << "Parent(string s) : " << s << endl;
% M* y0 p/ p# o4 ?0 g! d& p% E3 H    }2 ?/ A% j% Z% e: V/ z& n1 C: F& m
};! D( ]3 t: l3 f0 |' ^; t3 i

2 `/ v6 `4 X' a! Y7 ^; bclass Child : public Parent" T: z" G" a! T8 i0 ?
{
: N! B  Z7 q8 {4 C* R3 L, Y5 zpublic:
8 ?( M: D- X# A2 N6 l    Child()2 t* F, n1 I1 N3 Z: v
    {
6 A2 M+ o% a9 h        cout << "Child()" << endl;
7 {+ I; k! P$ E& [- N( U1 P# z    }9 K+ s. O) {# I- v
    Child(string s) : Parent(s)
! b/ S* P9 z1 u. _) D8 x! ^" q- k- p    {- ~% Q2 I1 A4 ?& g; a4 v' x0 N
        cout << "Child(string s) : " << s << endl;
2 U. c2 s/ B' F- m, d    }
, y% \- C# @0 {) H0 n+ i};
/ w' \' X/ W1 V! c0 R
* ]! P5 p+ @) b. Vint main()
% _5 m. \! s2 A! L5 Q( X' s{      
2 X7 s3 Q  U8 H) \    Child c;
" w( s6 C) O' L  M5 J  F6 X: H    Child cc("cc");* j' g# x6 S% F6 g  a, \
    + U( q+ j: \1 i7 t# Y. s" i4 L
    return 0;- N& Z3 U3 }" _; A1 |2 c3 X# A
}8 e9 F# k5 s( l  X
" m, g3 z+ B2 K: `5 C* Q
输出结果:
root@txp-virtual-machine:/home/txp# ./a.out; ^  Z4 `+ s4 Y% B
Parent()
7 k" `( R$ Q$ h: x/ t, K" gChild()
2 w" J2 ~8 s7 r7 q# ZParent(string s) : cc
* ?: Y) k- I& {6 i% s4 bChild(string s) : cc
; f* [' Z! Y* @, ]0 C6 ?1 s7 R  e9 o$ ~; Y6 U. M; E
注解:通过上面的代码输出结果,我们可以发现,子类定义的对象如果没有没有传参,就隐式调用父类的构造函数;当然上面也使用了显示调用,通过初始列表的就可以看出。
4、构造规则
  • 子类对象在创建时会首先调用父类的构造函数
  • 先执行父类构造函数再执行子类的构造函数
  • 父类构造函数可以被隐式调用或者显示调用
    2 y. x- J, L6 B! {" w
5、对象创建时构造函数的调用顺序
  • (1)调用父类的构造函数
  • (2)调用成员变量的构造函数
  • (3)调用类自身的构造函数
    3 g0 \' K' q  i/ h) J
总结:先父母,后客人,再自己
代码实践:
#include <iostream>. o# z6 c5 j. y" K/ U
#include <string>
+ G# N+ ^6 |' N9 N$ w- ]: I0 R9 r' n! o- P1 N
using namespace std;
8 R  w; `. N( K9 |- h+ G3 o, I4 t6 _7 \: F; G; }; K5 G
class Object4 i- l. K: d) u2 W
{3 _# L" t% j# @: }! |( [
public:
" {6 R  O% v! I9 b+ p    Object(string s)3 f! [+ W# V! w3 |
    {2 i% o- k; a5 B9 d  {
        cout << "Object(string s) : " << s << endl;
) g9 O% t/ q* @: `6 m% n* ]    }: K& w+ n, Y4 A) Y
};
6 Q8 Z; J- P8 F, f0 _' H, ]. z0 I6 }; d/ M
class Parent : public Object
9 s) b) x' A0 x$ U{& y& V& p% [% U/ b0 M
public:5 C% a: ^' q" {
    Parent() : Object("Default")
3 n, @& U+ Q( b) f* y    {& e4 w) S& V, Y
        cout << "Parent()" << endl;) l: {7 [, B9 E$ ?
    }
6 `$ o6 u$ x0 i3 A, S, j/ \. l7 P    Parent(string s) : Object(s)
0 g) m  s1 L% [( {; u3 @. a/ H" i    {+ ]" P, B+ o9 ?% K2 ]
        cout << "Parent(string s) : " << s << endl;
3 \/ T5 p# B' F2 v* H    }
6 E# R# @& D+ O% ~3 k# G};
) f/ ]3 A* s  ^3 o
3 m7 Q/ C9 K: I5 N/ _% B7 Oclass Child : public Parent
( S1 E1 x; L% U# I: B* h$ l6 @{
$ X) q4 P8 Q# j$ c    Object mO1;$ e4 F# T+ c( q; b- H, n
    Object mO2;
3 Z* X# `4 K+ J+ {2 L% spublic:
6 C: g8 `. H, m6 Z9 @    Child() : mO1("Default 1"), mO2("Default 2")2 s# f; _4 U' f: V
    {0 y* z3 J: `8 G4 R6 R) r. F
        cout << "Child()" << endl;( Z) m* N& W0 b5 ?7 b* S! H
    }
( p! T$ p0 B7 w3 M$ I    Child(string s) : Parent(s), mO1(s + " 1"), mO2(s + " 2")7 k0 a' A7 p2 e) V. ]3 p
    {
, I% v5 h! r5 U        cout << "Child(string s) : " << s << endl;: [0 z" l% D& e5 g2 G
    }
3 ]5 O3 k6 q9 ]  K4 s) n};( K2 L* Z  n5 O% W4 W/ |- C9 \

) U! H" B* w8 g1 y5 ^5 E! Mint main()
% O. M6 O# ^* S4 D  ?- d{       ' K* S$ B, q: N2 n
    Child cc("cc");" {/ i8 ?7 [4 A' V; o
   
9 j" ~5 ?  t1 R$ P9 e    return 0;  x9 q3 ~; B" `4 D4 J
}+ [7 q. ]3 V' h) d" ^& W4 N' D; P7 W

* S. [) d& p  H9 g! C' s' g4 ^
输出结果:
root@txp-virtual-machine:/home/txp# ./a.out0 }1 V& V6 Q+ c" d
Object(string s) : cc5 \7 a) `! u8 k9 Y4 ~
Parent(string s) : cc! m0 W$ B' o% I) ~8 C) ~
Object(string s) : cc 1. }- N1 `* Q& F9 A  k: E
Object(string s) : cc 25 [6 ^+ m7 i, U8 d- [
Child(string s) : cc) b2 T- t6 b$ J, G/ S) Z

1 _1 I* ?/ h5 D' G2 E( b1 R$ ^) O8 m
注解:我们可以看到,先定义了一个Child对象,然后最先访问Object带参构造函数,然后再是Parent带参构造函数(说白了就是父类先触发),然后在子类Child中又包含了组合关系(也就是客人),然后Object类中的带参构造函数,最后再触发自身的带参构造函数。
二、子类对象的析构
1、析构函数的调用顺序与构造函数相反
  • (1)执行自身的析构函数
  • (2)执行成员变量的析构函数
  • (3)执行父类的析构函数
    2 _" M# B1 i# ~- E; C
代码实践:
#include <iostream>1 P( C6 ?8 M" d
#include <string>+ A/ f1 e, S" _: x

2 d) z( k5 s( eusing namespace std;
8 N; c# {1 J$ P2 K4 z# f- ~
! h; u! |% {4 qclass Object
0 B% w2 K  T' M# e* n{
- n$ N# H& S9 D4 P5 b3 J$ q8 U    string ms;
+ k, D) B- H% Upublic:
4 X( P3 R5 j6 _7 t8 ^. u    Object(string s)& w( _* ]" ~1 X# {
    {- h  ]. x+ ]0 g8 d+ a, I
        cout << "Object(string s) : " << s << endl;" U! E! d) I% j, x/ \5 m
        ms = s;
/ [7 q- k7 p, J    }( Y- A) ]: y0 _7 P* u3 }
    ~Object()* M; n/ _; ^8 J" k+ j
    {* t" b% a6 G1 Y# n& }; W/ ?
        cout << "~Object() : " << ms << endl;, E' w2 N& d/ \% g+ F
    }* p7 L9 m: i  t( ]% R8 V/ T
};
1 e5 K! z6 O- ^+ X, j" p% n8 P* K/ h- M( P: H3 U4 ^" ?
class Parent : public Object
6 c/ x4 p; q: V: P& C& |{9 ^& H  H, @5 p) F* r& X
    string ms;
. c8 d9 }  ]4 ]& ]% F) bpublic:( ?6 }3 |4 T7 s+ D
    Parent() : Object("Default")
) \9 u' P5 G# E6 t    {3 t/ E' [5 o7 p, Q
        cout << "Parent()" << endl;
. R+ }/ |4 g9 ?/ z        ms = "Default";3 e9 K+ }0 ]4 v" k9 h9 x) l) J: |
    }; g9 i3 K* O7 J. T) ]
    Parent(string s) : Object(s)* {" K) F5 h, _. n% n. f8 O
    {
# H* q: z, g; {2 \) d3 [  u        cout << "Parent(string s) : " << s << endl;# V0 Y% ^0 a5 D1 T
        ms = s;6 ?! \/ Z  k& F; y# D% t
    }3 k5 t) @- u# D& u, I" i9 o& R* C2 {3 Q: m
    ~Parent()% \; A# B0 e, x) B$ \% P* ^8 r1 j
    {1 @/ ~8 |7 T& F* }6 v* D3 }' k
        cout << "~Parent() : " << ms << endl;
, A9 h0 H3 `# K# x6 N    }
1 U" b; y9 H$ @3 y7 T% x1 r! L};
8 o! f, m% q: ~. B' S' [0 W5 z- X1 q  ~; Z8 K' ]* a
class Child : public Parent
$ A- ?6 l) X3 Q/ @- C3 I- n6 {3 R) R{
1 |3 ?) l/ v! H# v* N" W0 u    Object mO1;
# f, ]9 }* D. k: Q    Object mO2;
* a. c  ]5 B# x    string ms;6 H' |6 C- T1 `: o# M  U# r" u
public:- l8 E/ Z( q4 c" E+ j
    Child() : mO1("Default 1"), mO2("Default 2")1 y+ E5 h7 E7 k! o; X/ H2 b
    {
. n3 p, k5 [  d# S+ i, C3 q        cout << "Child()" << endl;
+ @" T9 K0 Y0 l% w! T7 ]" b        ms = "Default";
. }6 S6 U& `8 Q9 y    }/ A3 t8 t1 Z, a2 B. S
    Child(string s) : Parent(s), mO1(s + " 1"), mO2(s + " 2")# t3 n% i- s* r& i4 e
    {. Z3 J) G/ n; K2 ?( c! d' P. a  y" t
        cout << "Child(string s) : " << s << endl;
/ I) P- \# w, A9 J! [( g        ms = s;7 `. N  G) e. W2 K6 H0 N
    }
- D1 [# A8 [; T. s: @- P) B  t    ~Child()# f/ ~: T1 q8 l% \. l6 J) S
    {
- Q" R2 A) v! ]  I  z+ y        cout << "~Child() " << ms << endl;
' L* F( Y# p% D, A) }    }& d6 x3 o/ f6 N3 I. v0 v0 i
};: F  J: L& j: F2 i) h9 V
- }5 a+ c+ b1 _# ]- U7 g# u; r+ q8 h7 X
int main()
  {4 D+ }2 |3 O( J{      
. W. Q6 T& \; U    Child cc("cc");0 {$ Y( E7 Z; X) s* a
    2 R4 h! m  t: B* e+ n* D
    cout << endl;
) ]& S: s: L' \4 \7 ]   
' c& Y( s/ Z1 B2 G2 w    return 0;
4 J* {; M; b9 Q. k3 q) n}
5 [7 M- a. M$ m3 y& ~( w# w1 D) Y+ M& u3 X
输出结果:
root@txp-virtual-machine:/home/txp# ./a.out" \; W, V: f3 u& }0 T' a) `
Object(string s) : cc8 F5 H2 M, v) r" q; Z
Parent(string s) : cc
' q3 {1 m& [. p: ?& Q' \3 l& KObject(string s) : cc 18 ^( F4 M- l! C: q0 h
Object(string s) : cc 2) n4 g1 R& O8 U' H
Child(string s) : cc4 _$ G+ \! Y0 q1 j0 H: J5 Q
0 \' K4 z! q6 Q
~Child() cc
& d* r2 g# f/ `7 l~Object() : cc 2
$ h- q& Q" _% Y9 k: k, Z~Object() : cc 1- @; O0 n& y; @8 S+ s+ p$ J
~Parent() : cc: s) e1 X- ^. f# x' ~/ }  P
~Object() : cc
4 `5 Q! E+ T7 E2 H/ ?# C
$ d) B- G% b! g9 i
三、总结:
  • 子类对象在创建时需要调用父类构造函数进行初始化
  • 先执行父类构造函数然后执行成员的构造函数
  • 父类构造函数显示调用需要在初始化列表中进行
  • 子类对象在销毁时需要调用父类析构函数进行清理
  • 析构顺序与构造顺序对称相反
    4 \6 T6 k6 ]* `
好了,今天的分享就到这里,如果文章中有错误或者不理解的地方,可以交流互动,一起进步。

% W6 U3 E. ^1 r
赞 收藏 评论0 发布时间:2020-8-21 10:03

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版