C++构造函数

参考:C++-copy constructor、copy-assignment operator、destructor

     Copy constructors, assignment operators, and exception safe assignment

C++在对象的不同创建方法中,会调用不同的构造函数,下面的代码探讨了调用一般的默认构造函数和复制构造函数的情形

 1 #include <iostream>
 2 using namespace std;
 3 
 4 class A
 5 {
 6 private:
 7     int v;
 8 public:
 9     A()
10     {
11         v = 0;
12         cout << "object created" << endl;
13     }
14     A(const A& a) { cout << "copy construct - const" << endl;}
15     A(A& a) { cout << "copy construct" << endl;}
16     ~A() { cout << "object deleted" << endl; }
17     void setvalue(int value = 6);
18     int getvalue() { return v; }
19 };
20 
21 void A::setvalue(int value)
22 {
23     v = value;
24 }
25 
26 void ReferenceA(A& a)
27 {
28     cout << "Reference a" << endl;
29 }
30 
31 void ParameterA(A a)
32 {
33     cout << "Parameter a" << endl;
34 }
35 
36 int main()
37 {
38     A a1;                //calls A(), before function return, calls ~A()
39     A *b = new A();      //calls only A()
40     delete b;            //calls only ~A(), it must be with new
41 
42     A a2 = a1;           //calls A(const A& a), before function return, calls ~A()
43     A a3(a1);            //calls A(const A& a), before function return, calls ~A()
44     A(a4);               //calls A(), before function return, calls ~A()
45     //A a6 = A(a5);      //error: a5 no declaration
46     A a6 = A(a4);        //calls A(const A& a), before function return, calls ~A()
47     //A *a8 = new A(a7); //error: a7 no declaration
48     A *a8 = new A(a1);   //calls only A(const A& a)
49     delete a8;           //calls only ~A(), it must be with new
50     ReferenceA(a1);      //don't call construction
51     ParameterA(a1);      //calls A(const A& a), before function ParameterA return, calls ~A()
52 
53     a1.setvalue();
54     cout << "v = " << a1.getvalue() << endl;
55     //system("pause");
56 
57     return 0;
58 }
View Code

在上述代码中,要注意函数的默认参数只能出现在函数的定义或声明中,不能同时出现在定义和声明中。同时要说明的是,如果同时存在A(const A& a)和A(A& a),若出现了调用复制构造函数的情况,将会优先调用A(A& a)。

使用msvc2013编译器所得结果如下

object created
object created
object deleted
copy construct
copy construct
object created
copy construct
copy construct
object deleted
Reference a
copy construct
Parameter a
object deleted
v = 6
object deleted
object deleted
object deleted
object deleted
object deleted

使用gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4)编译器所得结果如下

object created
object created
object deleted
copy construct
copy construct
object created
copy construct
copy construct
object deleted
cite a
copy construct
call a
object deleted
v = 6
object deleted
object deleted
object deleted
object deleted
object deleted

可见二者的运行结果是一样的。

下面是一个C++构造函数调用的具体的例子,由于类中没有给出复制构造函数的定义导致了意想不到的问题。

strngbad.h

 1 // strngbad.h -- flawed string class definition
 2 #include <iostream>
 3 #ifndef STRNGBAD_H_
 4 #define STRNGBAD_H_
 5 class StringBad
 6 {
 7 private:
 8     char *str;                 // pointer to string
 9     int len;                   // length of string
10     static int num_strings;    // number of objects
11 
12 public:
13     StringBad(const char * s); // constructor
14     StringBad();               // default constructor
15     ~StringBad();              // destructor
16 // friend function
17     friend std::ostream& operator<<(std::ostream & os,
18                          const StringBad & st);
19 };
20 #endif
View Code

strngbad.cpp

 1 // strngbad.cpp -- StringBad class methods
 2 #include <cstring>                          // string.h for some
 3 #include "strngbad.h"
 4 using std::cout;
 5 
 6 // initializing static class member
 7 int StringBad::num_strings = 0;
 8 
 9 // class methods
10 
11 // construct StringBad from C string
12 StringBad::StringBad(const char * s)
13 {
14     len = std::strlen(s);                   // set size
15     str = new char[len + 1];                // allot storage
16     std::strcpy(str, s);                    // initialize pointer
17     num_strings++;                          // set object count
18     cout << num_strings << ": "" << str
19          << "" object created
";          // For Your Information
20 }
21 
22 StringBad::StringBad()                      // default constructor
23 {
24     len = 4;
25     str = new char[4];
26     std::strcpy(str, "C++");                // default string
27     num_strings++;
28     cout << num_strings << ": "" << str
29          << "" default object created
";  // FYI
30 }
31 
32 StringBad::~StringBad()                     // necessary destructor
33 {
34     cout << """ << str << "" object deleted, ";   // FYI
35     --num_strings;                          // required
36     cout << num_strings << " left
";       // FYI
37     delete [] str;                          // required
38 }
39 
40 std::ostream& operator<<(std::ostream & os, const StringBad & st)
41 {
42     os << st.str;
43     return os; 
44 }
View Code

vegnews.cpp

 1 // vegnews.cpp -- using new and delete with classes
 2 // compile with strngbad.cpp
 3 #include <iostream>
 4 using namespace std;
 5 
 6 #include "strngbad.h"
 7 
 8 void callme1(StringBad &);  // pass by reference
 9 void callme2(StringBad);    // pass by value
10 
11 int main()
12 {
13     using std::endl;
14     StringBad headline1("Celery Stalks at Midnight");
15     StringBad headline2("Lettuce Prey");
16     StringBad sports("Spinach Leaves Bowl for Dollars");
17     cout << "headline1: " << headline1 << endl;
18     cout << "headline2: " << headline2 << endl;
19     cout << "sports: " << sports << endl;
20     callme1(headline1);
21     cout << "headline1: " << headline1 << endl;
22     callme2(headline2);
23     cout << "headline2: " << headline2 << endl;
24     cout << "Initialize one object to another:
";
25     StringBad sailor = sports;
26     cout << "sailor: " << sailor << endl;
27     cout << "Assign one object to another:
";
28     StringBad knot;
29     knot = headline1;
30     cout << "knot: " << knot << endl;
31     cout << "End of main()
";
32     
33     return 0;
34 }
35 
36 void callme1(StringBad & rsb)
37 {
38     cout << "String passed by reference:
";
39     cout << "    "" << rsb << ""
";
40 }
41 
42 void callme2(StringBad sb)
43 {
44     cout << "String passed by value:
";
45     cout << "    "" << sb << ""
";
46 }
View Code

使用msvc2013编译器所得结果如下

1: "Celery Stalks at Midnight" object created
2: "Lettuce Prey" object created
3: "Spinach Leaves Bowl for Dollars" object created
headline1: Celery Stalks at Midnight
headline2: Lettuce Prey
sports: Spinach Leaves Bowl for Dollars
String passed by reference:
    "Celery Stalks at Midnight"
headline1: Celery Stalks at Midnight
String passed by value:
    "Lettuce Prey"
"Lettuce Prey" object deleted, 2 left
headline2: 葺葺葺葺葺葺葺葺
Initialize one object to another:
sailor: Spinach Leaves Bowl for Dollars
Assign one object to another:
3: "C++" default object created
knot: Celery Stalks at Midnight
End of main()
"Celery Stalks at Midnight" object deleted, 2 left
"Spinach Leaves Bowl for Dollars" object deleted, 1 left
"葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺." object deleted, 0 left

使用gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4)编译器所得结果如下

1: "Celery Stalks at Midnight" object created
2: "Lettuce Prey" object created
3: "Spinach Leaves Bowl for Dollars" object created
headline1: Celery Stalks at Midnight
headline2: Lettuce Prey
sports: Spinach Leaves Bowl for Dollars
String passed by reference:
    "Celery Stalks at Midnight"
headline1: Celery Stalks at Midnight
String passed by value:
    "Lettuce Prey"
"Lettuce Prey" object deleted, 2 left
headline2: 
Initialize one object to another:
sailor: Spinach Leaves Bowl for Dollars
Assign one object to another:
3: "C++" default object created
knot: Celery Stalks at Midnight
End of main()
"Celery Stalks at Midnight" object deleted, 2 left
"Spinach Leaves Bowl for Dollars" object deleted, 1 left
"�v" object deleted, 0 left
*** Error in `/media/xzgz/Code/practice/Code/C++/c++_project/CPlusGrammer/build-cpg-Desktop-Debug/cpg': double free or corruption (fasttop): 0x000000000076a080 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f62bf89b7e5]
/lib/x86_64-linux-gnu/libc.so.6(+0x8037a)[0x7f62bf8a437a]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7f62bf8a853c]
/media/xzgz/Code/practice/Code/C++/c++_project/CPlusGrammer/build-cpg-Desktop-Debug/cpg[0x400cd5]
/media/xzgz/Code/practice/Code/C++/c++_project/CPlusGrammer/build-cpg-Desktop-Debug/cpg[0x40102c]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f62bf844830]
/media/xzgz/Code/practice/Code/C++/c++_project/CPlusGrammer/build-cpg-Desktop-Debug/cpg[0x400a09]
======= Memory map: ========
00400000-00402000 r-xp 00000000 08:05 619273                             /media/xzgz/Code/practice/Code/C++/c++_project/CPlusGrammer/build-cpg-Desktop-Debug/cpg
00601000-00602000 r--p 00001000 08:05 619273                             /media/xzgz/Code/practice/Code/C++/c++_project/CPlusGrammer/build-cpg-Desktop-Debug/cpg
00602000-00603000 rw-p 00002000 08:05 619273                             /media/xzgz/Code/practice/Code/C++/c++_project/CPlusGrammer/build-cpg-Desktop-Debug/cpg
00758000-0078a000 rw-p 00000000 00:00 0                                  [heap]
7f62b8000000-7f62b8021000 rw-p 00000000 00:00 0 
7f62b8021000-7f62bc000000 ---p 00000000 00:00 0 
7f62bf51b000-7f62bf623000 r-xp 00000000 08:09 2753340                    /lib/x86_64-linux-gnu/libm-2.23.so
7f62bf623000-7f62bf822000 ---p 00108000 08:09 2753340                    /lib/x86_64-linux-gnu/libm-2.23.so
7f62bf822000-7f62bf823000 r--p 00107000 08:09 2753340                    /lib/x86_64-linux-gnu/libm-2.23.so
7f62bf823000-7f62bf824000 rw-p 00108000 08:09 2753340                    /lib/x86_64-linux-gnu/libm-2.23.so
7f62bf824000-7f62bf9e4000 r-xp 00000000 08:09 2753345                    /lib/x86_64-linux-gnu/libc-2.23.so
7f62bf9e4000-7f62bfbe4000 ---p 001c0000 08:09 2753345                    /lib/x86_64-linux-gnu/libc-2.23.so
7f62bfbe4000-7f62bfbe8000 r--p 001c0000 08:09 2753345                    /lib/x86_64-linux-gnu/libc-2.23.so
7f62bfbe8000-7f62bfbea000 rw-p 001c4000 08:09 2753345                    /lib/x86_64-linux-gnu/libc-2.23.so
7f62bfbea000-7f62bfbee000 rw-p 00000000 00:00 0 
7f62bfbee000-7f62bfc04000 r-xp 00000000 08:06 669579                     /media/xzgz/Ubuntu/Ubuntu/Caffe/anaconda2/lib/libgcc_s.so.1
7f62bfc04000-7f62bfe03000 ---p 00016000 08:06 669579                     /media/xzgz/Ubuntu/Ubuntu/Caffe/anaconda2/lib/libgcc_s.so.1
7f62bfe03000-7f62bfe04000 rw-p 00015000 08:06 669579                     /media/xzgz/Ubuntu/Ubuntu/Caffe/anaconda2/lib/libgcc_s.so.1
7f62bfe04000-7f62bff76000 r-xp 00000000 08:06 711828                     /media/xzgz/Ubuntu/Ubuntu/Caffe/anaconda2/lib/libstdc++.so.6
7f62bff76000-7f62c0176000 ---p 00172000 08:06 711828                     /media/xzgz/Ubuntu/Ubuntu/Caffe/anaconda2/lib/libstdc++.so.6
7f62c0176000-7f62c0180000 r--p 00172000 08:06 711828                     /media/xzgz/Ubuntu/Ubuntu/Caffe/anaconda2/lib/libstdc++.so.6
7f62c0180000-7f62c0182000 rw-p 0017c000 08:06 711828                     /media/xzgz/Ubuntu/Ubuntu/Caffe/anaconda2/lib/libstdc++.so.6
7f62c0182000-7f62c0186000 rw-p 00000000 00:00 0 
7f62c0186000-7f62c01ac000 r-xp 00000000 08:09 2753323                    /lib/x86_64-linux-gnu/ld-2.23.so
7f62c0384000-7f62c0389000 rw-p 00000000 00:00 0 
7f62c03a8000-7f62c03ab000 rw-p 00000000 00:00 0 
7f62c03ab000-7f62c03ac000 r--p 00025000 08:09 2753323                    /lib/x86_64-linux-gnu/ld-2.23.so
7f62c03ac000-7f62c03ad000 rw-p 00026000 08:09 2753323                    /lib/x86_64-linux-gnu/ld-2.23.so
7f62c03ad000-7f62c03ae000 rw-p 00000000 00:00 0 
7ffece974000-7ffece995000 rw-p 00000000 00:00 0                          [stack]
7ffece9a0000-7ffece9a2000 r--p 00000000 00:00 0                          [vvar]
7ffece9a2000-7ffece9a4000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

需要注意的是,在StringBad类中,static int num_strings是静态成员变量,它由该类实例化的所有对象所共享,不能在类声明中初始化静态成员变量,可以在类声明之外使用单独的语句来进行初始化。

原文地址:https://www.cnblogs.com/pursuiting/p/7476437.html