C++基础_03

构造函数和析构函数执行的顺序

#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
using namespace std;
class Test{
public:
    Test(char * name){
        memset(this->name,0,sizeof(this->name));
        strcpy(this->name,name);
        cout<<"Test()->Name = "<<name<<endl;
    }
    ~Test(){
        cout<<"~Test()->Name = "<<name<<endl;
    }
protected:

private:
    char name[64];
};


void run()
{   //#1
    Test t1("t1");
    Test t2("t2");
}   //#2

void run2()
{//#1
    Test t1("t1");
}//#2

int main(int argc, char *argv[])
{   run2()// #1 -> t1的构造函数 -> #2 -> t1的析构函数
    run();// #1 -> t1的构造函数 -> t2的构造函数 -> #2 -> t2的析构函数 -> t1的析构函数 
    return 0;
}

构造函数的调用时机

#include <iostream>
using namespace std;

class Test{
public:
    //构造函数分类:无参,有参和拷贝
    //无参构造函数
    Test(){
        cout<<"Test(void)"<<endl;
    };
    //带参构造函数
    Test(int a){
        cout<<"Test(int )"<<endl;
    }
    Test(int a,int b){
        cout<<"Test(int ,int )"<<endl;
    }
    //拷贝构造函数
    Test (const Test &object){
        cout<<"Test(const Test & )"<<endl;
    }

};



int main(int argc, char *argv[])
{
    //如果类没有提供构造函数,C++会默认提供一个无参构造函数和一个拷贝构造函数

    //调用无参构造函数
    Test t1;//OK
//    Test t1(); //Error

    //调用带参构造函数
    Test t2(5);//OK
    Test t3 = (4,5);//OK ==> (4,5)会被当成逗号表达式,最终调用的其实是 Test(int),若是不存在[Test(int)]则编译器报错

    //使用匿名对象调用构造函数
    Test t4 = Test(1,2); //OK ==> Test(int ,int) 


    //调用拷贝构造函数
    Test t5(10,20);
    Test t6 = t5;//调用的是拷贝构造函数
    Test t7(t5);//调用的是拷贝构造函数

    Test one,two;
    one = two;//调用的是赋值函数,没有调用构造函数

    return 0;
}

拷贝构造函数的调用时机



#include <iostream>
using namespace std;

class Location{
private:
    int x;
    int y;
public:
    Location(){
        cout<<"Test()"<<endl;
    }
    ~Location(){
        cout<<"~Test()"<<endl;
    }
    Location(int x,int y){
        cout<<"Location(int ,int )"<<endl;
        this->x = x;
        this->y = y;
    }
    Location (const Location & location){
        this->x = location.x;
        this->y = location.y;
        cout<<"Location(const Location & location)"<<endl;
    }

public:
    void show(){
        cout<<"x = "<<x<<" y = "<<y<<endl;
    }
};

void copy(Location L)//传参过程执行的是拷贝构造函数
{                               //#1
    L.show();
}                               //#2

void run() 
{                               //#1
    Location L_one(100,200);    //#2
    copy(L_one);                //#3
}                               //#4

/*
run函数 
    run#1 -> run#2:L_one的构造函数 -> run#3:copy(L_one)[L_one执行拷贝构造函数] -> copy:#1 -> copy#2:L的析构函数 ->  run#4:L_one的析构函数 
*/



//当函数的返回值是一个类的类型的时候[类的类型,仅指(Location),并非(Location * 或 Location &)],函数 return 的时候也会执行拷贝构造函数
//这里仅指VS2012的编译器,GCC并不支持这一做法
Location getLocation()
{                               //#1
    Location Lo(7,8);
    return Lo;                  //#2 //函数的返回值是一个元素(class)C++编译器会返回以一个新的匿名对象
}                               //#3

void run2(){                    //#1

    getLocation();  // 函数返回的时候没有(Location)对象被接收  -> "[匿名Location对象]~Test()"

}                               //#2

/*
run2函数

    VS2013:
        run2#1: -> getLocation#1 -> getLocation#2[
                                                    1):Lo执行拷贝构造函数 Test(cosnt Test &) 创建一个匿名的Location对象.
                                                    2):Lo执行析构函数 ~Test()
                                                 ] -> getLocation#3: 返回匿名Location对象 -> run2#2:匿名Location对象执行析构函数 ~Test() 


    QT5.7:
        run2#1: -> getLocation#1 -> getLocation#2 -> getLocation#3: 返回自身(Lo对象) -> run2#2:Lo 对象执行析构函数 ~Test()

*/


void run3(){                    //#1

    Location LoL = getLocation();//#2  // 函数返回时有匿名对象接收 -> C++编译器会把匿名对象直接转成LoL,并不会执行拷贝构造函数
    LoL.show();

}                               //#3 

/*
run3函数
    VS2013:
        run3#1: -> getLocation#1 -> getLocation#2[
                                                    1):Lo执行拷贝构造函数 Test(cosnt Test &) 创建一个匿名的Location对象.
                                                    2):Lo执行析构函数 ~Test()
                                                 ] -> getLocation#3: 返回匿名Location对象 -> run3#2:匿名Location对象直接转成LoL对象(不执行拷贝构造函数) 
                                                   -> run3#3:LoL执行析构函数 ~Test()


    QT5.7:
        run3#1: -> getLocation#1 -> getLocation#2 -> getLocation#3: 返回自身(Lo对象) -> run3#2:Lo 对象直接转成LoL对象(不执行拷贝构造函数) -> run3#3:LoL执行析构函数 ~Test()
*/


void run4(){                //#1


    Location Lol(4,5); //对象已经初始化
    Lol.show();
    Lol = getLocation();    //#2  //匿名对象会执行赋值操作直接复制给(Lol)然后执行析构函数
    Lol.show();

}                           //#3
/*
run4函数
    VS2013:
        run4#1: -> getLocation#1 -> getLocation#2[
                                                    1):Lo执行拷贝构造函数 Test(cosnt Test &) 创建一个匿名的Location对象.
                                                    2):Lo执行析构函数 ~Test()
                                                 ] -> getLocation#3: 返回匿名Location对象 
                                                   -> run4#2:匿名Location对象直接将值复制给(Lol),然后执行析构函数 ~Test() 
                                                   -> run4#3:Lol执行析构函数 ~Test()


    QT5.7:
        run4#1: -> getLocation#1 -> getLocation#2 -> getLocation#3: 返回自身(Lo对象) -> run4#2:Lo 对象直接将值直接复制给(Lol)然后执行析构函数 ~Test()
                -> run4#3:LoL执行析构函数 ~Test()
*/


int main(int argc, char *argv[])
{
//    run();
//    run2();
//    run3();
//    run4();
    return 0;
}

C++中的浅拷贝


#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

using namespace std;

class Name{

public:
    Name (const char * name){
        this->length = strlen(name);
        this->name = (char *)malloc(this->length + 1);
        strcpy(this->name,name);
    }
    ~Name(){
        if (this->name != NULL){
            free(this->name);
            this->name = NULL;
            this->length = 0;
        }
    }

    //解决方案:
    /*
    Name (const Name & N){
        this->length = N.length;
        this->name = (char *)malloc(this->length + 1);
        strcpy(this->name,N.name);
    }
    */


public:
    void show(){
        cout<<"Name = "<<this->name<<endl;
    }
private:
    char * name;
    int length;
};

void run(){
    Name N_1("yzh"); // N_1执行构造函数初始化
    {
        Name N_2 = N_1;

        // 在没有 [解决方案] 的前提下
        /*
        N_2执行Name类默认的拷贝构造函数来初始化(浅拷贝),则
        N_2的成员变量Name并未重新分配内存,而是指向了N_1的Name所在的内存,即N_1的Name和N_2的Name指向的是同一片内存
        当程序执行到[ #2 ]处的时候,N_2执行析构函数,N_2的Name所处的内存被回收
        当在[ #2 ]之后再次执行[ N_1.show(); ]的时候,会因为内存已经被回收而导致程序出现错误
        */

        N_1.show();
        N_2.show(); //Name = yzh;
    }//#2

    N_1.show(); // 不存在[解决方案]的时候 Name = 垃圾值
}

int main(int argc, char *argv[])
{
    run();
    return 0;
}

构造函数初始化列表:
1)B类中组合了A类对象
2)A类设计了构造函数

#include <iostream>
using namespace std;

class A{
public:
    A(int a){
        cout<<"A = "<<a<<endl;
        this->a = a;
    }
    ~A(){
        cout<<"~A = "<<a<<endl;
    }
private:
    int a;
};


//B类中含有A类的对象
class B{
public:
    //利用B类构造函数的初始化列表来初始化A类
    B(int a,int b):A_two(b),A_one(a) //初始化列表顺序
    {
        this->a = a;
        this->b = b;
        cout<<"B"<<endl;
    }

    ~B(){
        cout<<"~B"<<endl;
    }

private:
    int a;
    int b;
    //定义的顺序
    A A_one;
    A A_two;
};

void run(){
    B b(1,2);

    /*
        1)按照定义的顺序通过构造函数列表执行A类的构造函数,A类的构造函数执行完毕之后才是B类的构造函数
        2)构造函数的执行顺序和析构函数执行的顺序相反
        A_one构造函数 -> A_two构造函数 -> B 的构造函数 -> B 的析构函数 -> A_two的析构函数 -> A_one的析构函数
    */
}

int main(int argc, char *argv[])
{

    run();

    return 0;
}

构造函数列表执行顺序

#include <iostream>

using namespace std;

class A{
public:
    A(int a,int b){
        this->a = a;
        this->b = b;
        cout<<"A = "<<a<<" B = "<<b<<endl;
    }
    ~A(){
        cout<<"~A"<<endl;
    }
private:
    int a;
    int b;
};

class B{
public:
    B(int a,int b):A_1(a,b),A_2(a,b),m(b),n(a)
    {
        cout<<"M = "<<m<<" N = "<<n<<endl;
    }
    B(const B & sb):A_1(sb.m,sb.n),A_2(sb.n,sb.m)
    {
        this->m = sb.m;
        this->n = sb.n;
        cout<<"B (const B &)"<<endl;
    }
    ~B(){
        cout<<"~B"<<endl;
    }

public:
    void show(){
        cout<<"SHOW: M = "<<m<<" N = "<<n<<endl;
    }

private:
   int m;
   int n;
   A A_1;
   A A_2;
};

void getShow(B sb){
    sb.show();
}


void run(){
    B sb(22,99);
    getShow(sb);
}

int main(int argc, char *argv[])
{
    run();

/*
//从B的普通构造函数进入
A = 22 B = 99  A_1构造
A = 22 B = 99  A_2构造
M = 99 N = 22  sb构造
//从B的拷贝构造函数进入
A = 99 B = 22  A_1构造
A = 22 B = 99  A_2构造
B (const B &)  sb的拷贝构造
SHOW: M = 99 N = 22 sb的show函数
//析构函数逆序执行
~B
~A
~A
~B
~A
~A
*/

    return 0;
}

匿名对象的生命周期

#include <iostream>

using namespace std;

class Test{
public:
  Test(){
      cout<<"Test"<<endl;
  }
  ~Test(){
      cout<<"~Test()"<<endl;
  }
};

void run(){
    cout<<"#1"<<endl;
    Test();//初始化一个匿名对象
    cout<<"#2"<<endl;
    Test t;//初始化一个名为t的对象
//    Test t();//Error
    cout<<"#3"<<endl;
}

/*
    #1 -> "Test()" -> "~Test()" -> #2 -> "Test()" -> #3 -> "~Test()"
    //匿名对象会在 #2 之前被析构掉
    //t对象会在run函数的"}"结束之后被析构掉
*/

int main(int argc, char *argv[])
{
    run();
    return 0;
}

构造函数调用构造函数

#include <iostream>

using namespace std;

class Test{

public:
    Test(int a,int b){
        this->a = a;
        this->b = b;

        Test(a,b,100); //产生一个匿名对象,构造之后马上被析构掉了,根本无法为变量c赋值

    }
    Test(int a,int b,int c){
        this->a = a;
        this->b = b;
        this->c = c;
    }

    ~Test(){
        cout<<"~Test()"<<endl;
    }

public:
    void show(){
        cout<<"SHOW: A = "<<a<<" B = "<<b<<" C = "<<c<<endl;
    }

private:
    int a;
    int b;
    int c;
};

void run(){
    Test t(1,2);
    t.show(); //c是一个垃圾值
}

int main(int argc, char *argv[])
{
    run();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值