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

c++——对象构造顺序和销毁

[复制链接]
gaosmile 发布时间:2020-8-4 23:01
一、对象的构造顺序:
1、对于局部对象:
当程序执行流到达对象的定义语句时进行构造。下面还是用代码来解析这句话:
#include <stdio.h>
3 l, I8 B$ h4 M. ?* E' w
' S; Z/ a3 c, r# N% _! Sclass Test
( c2 u) X& f$ `5 n9 U{
" x0 F; r. @) h8 F# a0 @  _' u     private:
1 _+ D4 {1 s9 Q# G. o& y% K        int mi;; k, V% g* i# l" C% w! }" ^7 J7 s
     public:
  d7 b: m2 n7 g        Test(int i)/ G; m: l; I3 d/ ?
        {( p" o1 P+ F0 @% L( B1 u
            mi=i;
" X: m. k# i2 d) Y  O" U            printf("Test(int i) is %d\n",mi);- i- `  P- v# H+ Q6 o$ U' l
        }& u1 S) H6 O% k9 x4 G: D) {0 x
        Test(const Test& obj)* r& h$ S% {2 n. ^5 M! S
        {# Q4 K3 z& B, V2 G# R" B$ h7 |
            mi=obj.mi;
) M7 e' a/ h! z            printf("Test(const Test&) obj is %d\n",mi);# ^/ J9 o$ k% n2 A
        }
+ q$ W" g7 ^: I% ?" z};% h/ V" P7 z4 D4 Z
int main()2 W) k$ g' D  ?3 h5 Z0 _( h
{& F' g9 }8 |( C5 o3 H% S  B

/ `  R: U! Y" ~/ H1 u! R+ U4 t    int i = 0 ;) N' T+ ^% z& E0 P3 o+ M
     Test a1 =i;//Test(int i):0
( z1 X& ~" }  b( Q     while(i<3)
) g% l6 L8 c! y( b, U' B- S, P     {0 A, Q  p1 l' \
        Test a2 = ++i;//Test(int i):1,2,3* w4 F/ M# h$ F  B
     }
1 _2 b2 C$ f8 @+ y% K" z; h9 O     if(i<4): B0 R: z: H) I2 C6 j
     {9 \8 X1 Z% x" m1 D& a
        Test a = a1; //Test(const Test& obj is :0
6 m$ @0 w' D+ t: [! A4 T$ [     }
2 C0 l" _  ?- G' {4 j9 @# i     else
% L1 W3 Y! ]/ R2 \) R& d     {  M; ^! |2 m. z( r
        Test a(100);
5 b, y" N7 _/ \) d' a* P6 |/ ?: U' W; [8 M/ V$ O7 n8 r
     }
9 m! z7 G; s* i* r" M! }0 B     return 0;$ L: p' @( n. x4 k
}1 e/ q, K2 S2 Z7 H& B% \
( s0 g, |. ]' D: Z: q1 \
输出结果:
Test(int i) is 0
9 D# j4 N, j  G4 ZTest(int i) is 1
8 L. p5 t& k2 P( @Test(int i) is 2+ P( @/ _" S$ ]7 s3 x" J8 |9 a
Test(int i) is 3
/ i1 C# d$ ^  x- ]Test(const Test& obj) is 0% h$ w0 U% q5 _8 ^
7 Y% H' R/ x( k- o; b
这里我们可以看出当程序流执行到相应的构造对象的那条执行语句时,就会调用构造函数(或者拷贝构造函数)。goto语句想必大家不陌生,但是都害怕这玩意,下面我们加入goto语句看看会产生什么现象:
#include <stdio.h>5 |9 R( A; A1 h9 f: Q6 f( u2 X
class Test{
; K% f3 c+ a$ a" J- ^  L( h) Bprivate:
6 ]0 Y+ f- Q6 Y' X- N/ i    int mi;
2 T+ B- e) M4 J9 w' f7 b! Ypublic:# c9 u! n6 y& W. C
    Test(int i)
( E, N  c$ q1 p% L   {
- M/ E& O/ o$ j" Y, ~- l        mi=i;, ]5 t1 e) g9 _/ h( d, R9 h: {9 {
        printf("Test(int i) is %d\n",mi);
" F. Z; I" @$ @3 z' e' f
, b- A7 e% L8 J    }& \1 y6 Y' x$ p6 d
    Test(const Test& obj)
' D7 a2 `4 j2 q; ]4 ^! f; i    {
7 a* A$ M4 T7 D  \/ h  I: m9 r       mi=obj.mi;
7 o& G+ S' P4 Q3 {       printf("Test(const Test& obj is %d\n",mi);
1 k6 g: N. u! j6 n& @) F3 Z: j1 i' d$ x+ R4 ^; \
    }
* q9 m1 X: R: V% `* }& N# U0 d
+ o. ]7 G) k0 L8 c% l# S$ O: z};
' o8 S3 [  I& X7 s; b- nint main()
# \7 @. u: _9 C; Z' {{/ g' C# o' p, v" A# z2 t
   int i = 0;  //Test(int i) :0: Z7 v1 k4 t0 n0 s
   Test a1 = i;
) J1 Z0 U& v/ M2 h   while( i <3)$ ~+ j" y- \/ x  Z+ g
   {# w2 ^- P+ a* R9 \
        Test a2 = ++i;  //Test(int i) :1,2,3
8 ?7 o# I+ {: q7 q# U    }# r) s/ Z3 O' @2 U! r0 J
goto end;
( l9 A7 ]; j6 j/ [( d2 P3 I' `- |   if(i <4)/ g4 `1 a8 i+ Q' B0 {
    {. I3 J* A+ }- L9 q
       Test a = a1;//Test(const Test&) obj is :0
6 A+ d: l, ]) E5 n# U  }4 ^- K6 @1 y) y5 h7 P$ b- q" W
    else
$ ]9 l+ `+ k/ I    {
# q4 N% e% X8 i8 J1 b       Test a(100);
* M& T' U7 ]! A7 f; K/ l- w     }4 p( ~/ [# D: Y8 w3 V% P
end:
# u: i( D- l. {) ]9 x( l0 `    return 0;
1 M$ I0 u5 z* a6 w3 S4 W' @& }# G  V3 M5 J}; K, E0 _% R0 q1 l2 T

# w% g& i" e2 [* R! l0 ~
输出结果:
Test(int i) is 0
+ x4 O% G" t- Z3 vTest(int i) is 1# M' p- A8 a  ?7 L" n
Test(int i) is 2
5 u2 J) c4 t6 ^5 J, p' _. uTest(int i) is 3

: `4 W! I' h* t" I
从结果我们可以看出从if那条语句就被跳过了,没有执行到,这里这样写的目的是为了引出,当你使用goto语句,把对象给屏蔽了,后面你不能使用这个对象了,不然程序会出现大问题:
#include <stdio.h>7 R" @& V$ u: ~: N  ~: C) s
class Test{2 A% r$ @3 X5 J
private:
4 u* u4 W* q) \; y    int mi;8 O# u6 K3 \* i% D  c1 s
public:6 Q; ]# D# y6 h0 P, A1 T. z
    Test(int i)# f& e# o9 D8 ?- p' q9 m
   {
3 N4 q# v0 r# a- ]$ @* @        mi=i;
1 v8 e8 F& m* w+ \- d6 ]        printf("Test(int i) is %d\n",mi);! I- G1 k* b# }# o2 }2 K8 X
6 X+ y4 V/ Z: h5 L
    }+ F; V. i& @* N) B) k# K
    Test(const Test& obj)& Z$ [9 x6 R# F9 }  V
    {# ~: v) z- J) ~
       mi=obj.mi;' k8 _8 m: U. w- h+ O6 u$ ], S
       printf("Test(const Test& obj is %d\n",mi);- r. g6 K1 J6 H$ v
    }9 o  G7 J" J: G  Z3 d
    int getMi()4 a: z) k8 ?2 q
     {
4 F- o+ F( h" R         return mi;
( H, a5 H0 z( ?7 k$ U: n3 g4 u     }' h) s2 V5 @- |. q0 K3 b" w9 X
};2 c: _. ^3 V; z" ?6 x9 K& k5 [
int main()
9 e) \2 Y  `9 v: J# T' }  c/ P{
# P+ t# x+ p. L: m6 y   int i = 0;  //Test(int i) :0
+ u5 d$ I8 @5 o' P. s" n   Test a1 = i;
8 x: n5 n0 ]# Q9 }   while( i <3)
. T& T+ H  F0 u3 a/ y   {9 ~1 ?) D. K1 P* g1 K, y
        Test a2 = ++i;  //Test(int i) :1,2,3
( F4 p  A0 n6 |4 u/ K  t1 H    }
0 X& K) X2 y4 T7 t6 q2 T4 Xgoto end;8 z7 \2 r7 k! n
      Test a(100);
# c% |: z: a6 }; w" y, Lend:
" |; H' |5 \& K) `3 H& s( O     printf("a.mi is %d\n",a.getMi());
+ `# ?- z1 n# r; K+ G% `. H. s$ |% [& G4 U9 G, B3 V% ^! E
    return 0;
4 K; x7 }3 `; }8 h; O}; h) D8 Q" N# i
0 e7 C: J" v6 _9 z; @  a
输出结果:
tt.cpp: In function ‘int main()’:
# b4 R7 r* @/ @: C% O" Xtt.cpp:32:1: error: jump to label ‘end’ [-fpermissive]8 x# n& {8 d% @3 i3 b1 L
end:' v. \4 F* K0 F2 j, ~! L
^0 y# j3 m# ]; n  q
tt.cpp:30:6: error:   from here [-fpermissive]
' c- W% Q' @( b5 O  x goto end;3 u+ O; {; R# h
      ^
/ T: H9 h1 S% |3 Z- I3 x0 mtt.cpp:31:12: error:   crosses initialization of ‘Test a’
: A5 l/ p8 W" Q. v: h: v5 @       Test a(100);; [& t5 h- B: H
            ^- q% [( h1 a- R

' W- _2 O7 [# H9 C4 b
这里就是上面所说了的,对象被goto语句给屏蔽了,后面就不能使用这个对象来进行操作了。
2、对于堆对象:
  • 当程序执行流到达new语句时创建对象
  • 使用new创建对象将自动触发构造函数的调用
    / W( ]0 P# ~# M& Y
代码演示:
#include <stdio.h>8 |  m( l- Q+ ]& ?! N
" {3 y% ]$ O! N
class Test
6 P2 `3 x, ?7 [1 {* d2 L6 A4 c0 _8 n{
9 @( Y7 y' p" X% V0 Tprivate:
. U( z1 T5 I& u- j6 D; L  {" [    int mi;7 \  S0 L3 G: _  l# X
public:( L$ s& @4 ]3 O- K
    Test(int i)4 e8 S' u# o& T% _! h) t. g
    {
! q5 C/ l  U& w( H  l        mi = i;
. ^. G4 t- ?' k7 i1 F, ?1 L7 H0 }        printf("Test(int i): %d\n", mi);
1 ~2 {; }( }/ T; K6 X# k* ?    }
8 T0 c: q; T7 R- d( q! i    Test(const Test& obj): o* x* e" r8 L( n1 _' T2 {, c1 x
    {$ r% ~+ g4 U+ r) f& D, @2 `, M
        mi = obj.mi;
& Q/ M2 ~1 ]5 v* K% L( h        printf("Test(const Test& obj): %d\n", mi);
: j5 n' H- S0 S( |    }
. J. i1 l+ G. A% J3 c    int getMi()
' w% N0 D$ \4 s+ T    {, l9 B# p" T1 N. D* o! t7 z
        return mi;$ m1 s* S$ S& c( i$ ^8 O8 x4 P/ _
    }
7 ~. N& M; }# c};
: E0 g$ _/ V% b5 _
8 ?  T8 ]8 g- _$ _' s3 Fint main()
# |1 ]/ v( Z! C6 y0 x{
( X. z7 `8 S) Y5 l    int i = 0;
* u' n, l% N) s: E6 s2 A: L    Test* a1 = new Test(i); // Test(int i): 0
' M; b3 k+ ]8 f0 S. o        
7 K# L, s0 P% T  `  \4 @) E3 F    while( ++i < 10 )1 }6 e& g% j/ _: K, H
        if( i % 2 )! }# f2 Q! f/ A! M
            new Test(i); // Test(int i): 1, 3, 5, 7, 9
2 {% w" L, _8 |5 w! v        
8 v. ~3 i! b" z6 Q9 U    if( i < 4 )
7 t0 b+ C( {' }2 B        new Test(*a1);$ I6 a5 \! U& B& ~9 m1 Z
    else" H1 l3 e  r$ [5 \5 ]9 L* ^8 O
        new Test(100); // Test(int i): 100' z+ ^6 A, ?9 g8 f" x3 r! }' n( g
        
0 V4 u8 ]. c) k    return 0;1 z( T% h/ i* q# y, c# k% Q
}4 K' g9 R! O4 T& ?

' |) f1 J+ M5 o% F- ]$ o
输出结果:
Test(int i): 0
2 [: [* A0 u' x4 H+ }2 ]! _) fTest(int i): 1
5 t" r1 r) l8 t: Q. y7 X: Q# ^Test(int i): 3
, W! e/ G/ J2 b5 Q+ ?Test(int i): 5! m6 `) t  ]4 F! c4 ^  ~
Test(int i): 7
3 S+ M0 c9 i- s$ U+ v; G3 P+ r1 `Test(int i): 92 O( G" b- H- |. u
Test(int i): 100+ {7 N0 V7 j; x( a
+ O8 l5 [' _* b7 s. q, ^8 ~3 V
3、对于全局对象:
  • 对象的构造顺序是不确定的
  • 不同的编译器使用不同的规则来确定构造顺序。

    7 ~1 _8 n3 m$ R2 G
同样还是来看代码示例,这里我创建了几个文件:tes1.cpp   test2.cpp   test3.cpp   test4.cpp    test.h;他们的内容如下:
test1.cpp:
#include "test.h"% K4 H) ?+ m! C- G, O

3 u: q9 p% Y$ O7 A# n* }: T! d# t- a5 [Test t4("t4");! B+ V  y& X* w+ o

* n0 G  R& n! h- m3 ?2 Lint main()1 ~8 r: N, i0 ]0 T/ q
{9 G" ?3 r3 o2 H* A' l- M  v' q
    Test t5("t5");
' B' x9 a% z  _" }0 s1 l, C; B}
" n$ P) }+ M' h& e7 }
test2.cpp:
#include "test.h"; K$ d, Z; X! L
- s1 k. m* n. L% P7 n. ?
Test t1("t1");
3 m" g& U; [: x6 b

7 }9 h- z* ~0 e
test3.cpp:
#include "test.h"
4 m  e4 ^) c# M5 d  P$ ~
6 [! R2 e7 E& D% K. @1 |6 A5 {6 Z% uTest t2("t2");  S7 ^0 G3 M6 w" l+ Y
9 q7 P( g# s0 [  ^$ A
test4.cpp:
#include "test.h"# _9 f- k9 r2 c. i9 I

1 ^5 m" \' `" j& N5 [% _Test t3("t3");, F! u% B7 F0 g& \
6 |! E2 Z" E3 k# `) q! ~- g- X; f
test.h:
#ifndef _TEST_H_3 @3 S6 t2 Z6 n- u8 h6 N/ O8 J
#define _TEST_H_
6 C; @  }5 j2 Z( V/ @: t4 C% a2 ~9 Q& O8 z+ a7 Q
#include <stdio.h>. g7 S9 v4 \# M2 t$ @

7 `$ t2 `8 M0 C- ~3 Z7 Rclass Test! O3 F  X/ O4 {5 W) E
{  V" O2 v+ _$ A$ F
public:6 ?$ ~+ j  |0 l2 x% N6 W  f
    Test(const char* s)2 W$ C4 n1 C8 Y# e2 d  \1 y4 d
    {
+ B! }' R  S+ E& [! Q- X        printf("%s\n", s);' h' D! B! a9 c, w4 B& R
    }
8 E. u# A& i, q7 N3 d6 E: n  ?};# E: i. ^) \7 Z

- G4 E5 C% L, {4 n0 f#endif
6 @3 u: d/ O3 m. H, _3 _
5 f1 S/ L. @/ z
最后输出结果:
root@txp-virtual-machine:/home/txp# g++ test1.cpp test2.cpp test3.cpp test4.cpp -o put/ {. _9 |3 I! I) N$ e0 L
root@txp-virtual-machine:/home/txp# ./put0 `7 d# ~" B! c% ^- t5 x
t48 D5 a, C3 c7 w- s9 Z
t1
! p0 d6 m6 g9 u0 ut2' g' _* D$ a' w
t3; ^  }, M( F! K, V  ~# Z
t5
7 A) c7 j6 W. f" V( H5 C3 t  ?$ b

/ D, c" ]8 N& t  n1 ?" B% \
4、小结:
  • 局部对象的构造顺序依赖程序的执行流
  • 堆对象的构造顺序依赖于new的使用顺序
  • 全局对象的构造顺序是不确定的

    : b" X9 N* u4 V7 T4 E( `
二、析构函数:
1、c++的类中可以定义一个特殊的清理函数,叫做析构函数,这个函数的功能与构造函数相反,顾名思义就是销毁的意思了。
2、定义:~ClassName()
  • 析构函数没有参数也没有返回值类型声明
  • 析构函数在对象销毁时自动被调用

    ' O9 _# n, I' Z4 G) M1 l6 F
代码示例:
#include <stdio.h>
9 k5 S9 A! y& J: d$ L% ~4 w5 a
. Q, q) L! l) X1 s. oclass Test" D  P3 e& D  O* M! f5 K( ^
{9 I& Q2 _! T+ m$ y# s# E
    int mi;
) d  H& U1 s) v+ y% Ipublic:
8 {) y4 D, v& ?8 ~    Test(int i)% W$ X/ g; W( C8 e  a
    {
9 `" b* X% y3 D* L        mi = i;$ q4 Z: q' y: ^; T0 o
        printf("Test(): %d\n", mi);
* H1 P1 W, J; l! q9 Q    }8 c; c4 x; q/ k0 c- D9 C
    ~Test()
: q0 ~4 A* c3 l6 i6 P% }! C    {% V0 S* f2 ^- A2 ?- S5 K/ l5 ?7 y
        printf("~Test(): %d\n", mi);
$ J  f. j- u0 Z9 H    }
2 B" X: q8 H& J( E};' B2 S* U: @6 C

4 Z3 r% [/ W+ aint main()
9 k. v9 x: H5 e- {- k: |{
) \, l7 I5 P1 T& W    Test t(1);
. O* |9 @; ^/ l2 _+ e5 N   
% t  A. l2 c8 q) ^% Y; ]. N    Test* pt = new Test(2);" i; P& p# [- \. i
    $ C- o# y7 e- |1 C& D/ s
    delete pt;
, a' V1 ?( W2 H0 H, I  d   
/ y! z$ y0 d: ^6 [4 E5 \    return 0;
, c) n; f% F3 Q& `2 T5 P' s}
; ?% q2 P: M% s
$ T5 r0 h: t; x7 y' C
输出结果:
Test(): 1
) Y  x/ n4 r+ J6 m2 x& uTest(): 24 W2 ]2 N% D. x& [0 V; v. L& S- L
~Test(): 2( H% G, e. D! }
~Test(): 1$ A& J1 }$ a# b. k" C7 l2 e/ y
! c% L; E1 s' b+ C  v* {7 c
3、析构函数的定义准则:
当类中自定义了构造函数,并且析构函数中使用了系统资源(比如说,内存的申请,文件打开),那么就需要自定义析构函数了。
4、小结:
  • 析构函数是对象销毁时进行处理的特殊函数
  • 析构函数在对象销毁时自动被调用
  • 析构函数是对象释放系统资源的保障
    & v# }4 T8 [8 ?: Q% ]
赞 收藏 评论0 发布时间:2020-8-4 23:01

举报

0个回答

所属标签

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