• 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是静态成员变量,它由该类实例化的所有对象所共享,不能在类声明中初始化静态成员变量,可以在类声明之外使用单独的语句来进行初始化。

  • 相关阅读:
    SpringBoot(十):SpringBoot的简单事务管理
    SpringBoot(九):SpringBoot集成Mybatis
    独立式智能扫码插座
    STC-51开发板-单片机控制数码管&按键&点阵综合操作
    单片机定时器与数码管静态显示
    半导体器件
    电路模型与规律
    单片机-引脚并行口结构讲解
    单片机-基础知识,存储原理,引脚简介———(第一个小程序)
    C语言-综合知识点
  • 原文地址:https://www.cnblogs.com/pursuiting/p/7476437.html
Copyright © 2020-2023  润新知