对象的构造与析构

Posted songhe364826110

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了对象的构造与析构相关的知识,希望对你有一定的参考价值。

1. 构造函数的定义

从程序设计的角度,类的对象只是变量,在栈上和堆上创建对象时,成员变量初始为随机值;创建全局对象时,成员变量初始为0值。

C++中可以定义与类名相同的特殊成员函数,叫做构造函数

  • 构造函数没有任何返回类型
  • 类的构造函数在对象定义时自动被调用,进行对象的初始化工作
  • 对象的定义和声明是不同的
Test t1;         //定义对象,为对象分配内存空间,并调用构造函数
extern Test t2;  //声明对象,告诉编译器存在这样一个对象

2. 构造函数的重载

  • 一个类中可以根据需要定义多个重载的构造函数
  • 构造函数的重载遵循C++重载的规则
#include <stdio.h>

class Test

public:
    Test()
    
        printf("Test()\\n");
    
    Test(int v)
    
        printf("Test(int v), v = %d\\n", v);
    
    Test(int v1, int v2)
    
        printf("Test(int v1, int v2), v1 = %d, v2 = %d\\n", v1, v2);
    
;

int main()

    Test t;        //调用 Test()
    Test t1(1);    //调用 Test(int v)
    Test t2 = 2;   //调用 Test(int v),只有一个参数时可以用赋值符号
    Test t3(1, 2); //调用Test(int v1, int v2)
    //Test t4 = ?; //多个参数时,不能用赋值符号

    int i(100);
    printf("i = %d\\n", i);

    return 0;

技术图片

对于多个重载的构造函数,在定义对象时C++会自动匹配选择使用哪一个,但在一些特殊情况下,可能需要显式调用构造函数,比如下面的例子。

#include <stdio.h>

class Test

private:
    int value;
public:
    Test()
    
        value = 0;
    
    Test(int v)
    
        value = v;
    
    int getValue()
    
        return value;
    
;

int main()

    Test t1[3];                              //自动调用构造函数,所有对象默认用Test()进行初始化
    Test t2[3] = Test(), Test(1), Test(2); //手动调用构造函数,对象使用Test(int v)进行初始化

    for (int i = 0; i < 3; i++)
    
        printf("t1[%d].value = %d\\n", i, t1[i].getValue());
    

    for (int i = 0; i < 3; i++)
    
        printf("t2[%d].value = %d\\n", i, t2[i].getValue());
    

    return 0;

技术图片

3. 两个特殊的构造函数

  • 有两个特殊的构造函数:无参构造函数拷贝构造函数(参数为const ClassName &的构造函数)
  • 当类中没有定义任何构造函数时,编译器默认提供一个函数体为空的无参构造函数
  • 当类中没有定义拷贝构造函数时,编译器默认提供一个浅拷贝的拷贝构造函数,进行简单的成员变量值的复制
#include <stdio.h>

class Test

private:
    int i;
    int j;
public:
    Test()
    
        i = 1;
        j = 2;
    
    Test(const Test &obj)
    
        i = obj.i;
        j = obj.j;
    
    int getI()
    
        return i;
    
    int getJ()
    
        return j;
    
;

int main()

    Test t1;       //调用无参构造函数
    Test t2 = t1;  //调用拷贝构造函数

    printf("t1.i = %d, t1.j = %d\\n", t1.getI(), t1.getJ());
    printf("t2.i = %d, t2.j = %d\\n", t2.getI(), t2.getJ());

    return 0;

技术图片

把代码第9-18行两个构造函数注释掉,看以看到运行结果和上面一致,只不过i和j的值变为了随机值。

技术图片

拷贝构造函数有深拷贝和浅拷贝之分:

  • 浅拷贝后对象的物理状态相同,深拷贝后对象的逻辑状态相同
  • 编译器提供的拷贝构造函数只进行浅拷贝

当对象中有成员指代了系统中的资源时,就需要进行深拷贝,比如:

  • 成员指向了堆空间内存
  • 成员打开了系统中的文件
  • 成员使用了系统中的网络端口
  • ......

作为程序设计的一般性原则,只要自定义拷贝构造函数,必然需要实现深拷贝!!!

#include <stdio.h>

class Test

private:
    int i;
    int j;
    int *p;
public:
    int getI()
    
        return i;
    
    int getJ()
    
        return j;
    
    int *getP()
    
        return p;
    
    Test(const Test &t)
    
        i = t.i;
        j = t.j;
        p = new int;
        *p = *t.p;
    
    Test(int v)
    
        i = 1;
        j = 2;
        p = new int;
        *p = v;
    
;

int main()

    Test t1(3);
    Test t2(t1);

    printf("t1.i = %d, t1.j = %d, t1.p = %p, *t1.p = %d\\n", t1.getI(), t1.getJ(), t1.getP(), *t1.getP());
    printf("t2.i = %d, t2.j = %d, t2.p = %p, *t2.p = %d\\n", t2.getI(), t2.getJ(), t2.getP(), *t2.getP());

    return 0;

技术图片

4. 初始化列表的使用

C++提供了初始化列表对成员变量进行初始化,语法规则为:

ClassName :: ClassName() : 
             m1(v1), m2(v1, v2), m3(v3)

    // some other initialize operation

关于初始化列表的使用,有以下几条规则:

  • const成员变量只能通过初始化列表初始化
  • 如果成员变量中有其他类的对象,那么这些对象也只能通过初始化列表初始化
  • 成员变量的初始化顺序与成员在类中的声明顺序相同,与初始化列表中的位置无关
  • 初始化列表先于构造函数的函数体执行
#include <stdio.h>

class Value

private:
    int mi;
public:
    Value(int i)
    
        printf("Value()::i = %d\\n", i);
        mi = i;
    
    int getI()
    
        return mi;
    
;

class Test

private:
    const int ci;
    Value m2;
    Value m3;
    Value m1;
public:
    Test() : m1(1), m2(2), m3(3), ci(100)
    
        printf("Test::ci = %d\\n", ci);
    
    int getCI()
    
        return ci;
    
    int setCI(int v)
    
        int *p = const_cast<int *>(&ci);
        *p = v;
    
;

int main()

    Test t;

    printf("t.ci = %d\\n", t.getCI());

    t.setCI(10);

    printf("t.ci = %d\\n", t.getCI());

    return 0;

技术图片

以上是关于对象的构造与析构的主要内容,如果未能解决你的问题,请参考以下文章

C++:对象和类|| 类的构造函数与析构函数

C++:对象和类|| 类的构造函数与析构函数

c++_构造与析构

c++_构造与析构

c++_构造与析构

C++ - 构造函数与析构函数的使用