C++快速入门--4

构造函数与析构函数

C++中构造函数在函数初始化的时候自动调用,名字跟类名一样,析构函数在对象销毁的时候自动调用,先创建的对象后销毁,栈模式,并且析构函数无任何返回值,通过析构函数,常用来释放某些资源。构造函数可以被重载,而析构函数不能被重载,因为析构函数无返回值和无参数决定了它只能拥有一个

class Test{
public:
    Test(){
        this->name = (char *)malloc(sizeof(char) * 100);
        cout<<"我是一个无参构造函数"<<endl; //构造函数,常常用来初始化某些属性
    }
    Test(int a){
        this->a = a;
        cout<<a<<endl; //有参构造函数,常常用来初始化某些属性
    }
    ~Test(){
        if(this->name){
            free(this->name);
        }
        cout<<"我是析构函数"<<endl; //析构函数,常常用来释放某些资源
    }
private:
    char * name;    
    int a;
}

值得注意的是,一个类中,会自动生成午参构造函数,不管你定义没有定义,都会自动生成,如果定义了有参构造函数,那么该类就不会再默认定义无参构造函数,所以你这里如果你想创建默认无初始化参数的对象,那么就需要自己在类中定义一个无参构造函数。

但是在C++中你可能会简单这样调用的构造函数的方法

Test t = 1;

这样写就等于调用了Test(int a)这个构造函数,当然,你可以使用逗号表达式,例如Test t = a+1,a

Test t1 = Test(1,2);

像如上这种写法,在早期的处理器中调用完Test类的Test(1,2)构造器后,又会调用t1的构造器,所以这里调用了2次构造函数,后面的编译器做了优化,Test(1,2)只会调用一次,并调用默认的拷贝构造函数,赋值给t2

C++中copy构造函数

在上面讲到的,Test t1 = Test(1,2);的时候,会调用Test类中的拷贝构造函数,将Test(1,2)匿名对象拷贝给t1,如下写法能帮助你更容易理解拷贝构造函数的使用方法

class T{
private:
    int a;
public:
    T(int a){
        this->a = a;
    }
};

int main(){
    T t1(1,2);
    T t2 = t1; //将t1对象赋值给t2
    return 0;
}

至于拷贝构造函数是如何实现的,我认为,它是将t1中的各个成员属性的值复制给了t2,我们甚至可以在拷贝构造函数中,实现我们自己需要的逻辑

class T{
class T{
private:
    int a;
public:
    T(int a){
        this->a = a;
    }
    T(const T & t){
        this.a = t.a + 100;
    }
    int getA(){
        return this->a;
    }
};

当你使用T t2 = t1的时候,这时候,会让a的值不是单纯的拷贝,而是在原来的基础+100,同样的,你还可以在这个拷贝函数中实现你需要的逻辑。这里你可能还会有另外一个疑惑,a明明是私有属性,原则上是不能被直接访问的,为什么这里还能能通过t.a来访问到呢,原因是,它们属于同一个类,编译器在找t的属性的时候,不会去通过对象作用域来访问,而是直接在当前类中访问,这一点,在java中也一样。

T t1;
T t2;
t2 = t1;

像这种情况,在t2=t1时,是不会调用任何构造函数,它只是一个赋值。
再来看如下写法

T newT(){
    T t(1,2);
    return t;
}

int main(){
    newT();
    return 0;
}

如上写法会调用一次拷贝构造函数,有人会感到奇怪,为什么会调用拷贝构造函数呢?其实是这样的,再newT()中,先通过一般构造函数生成t对象,然后通过拷贝构造函数,拷贝给一个匿名对象,然后再调用析构函数析构了t对象,这时候newT();这个函数就执行完了,最后main函数执行到最后,匿名对象也被析构

T t = newT();

如上写法也只会调用1次拷贝构造函数,2次析构函数,有人认为,这里newT()返回了一个匿名对象,然后通过拷贝构造函数,再将这个对象拷贝给新的t对象,再加上之前的那次拷贝构造函数,不是2次吗?哈哈哈,我之前也是这么理解的,但是,事实并非如此,C++设计者为了提高编译器效率,在这里做了优化,t = new T();不会再调用拷贝构造函数了,而是直接将匿名对象转换成了有名字的t对象。

再看如下写法

T t2;
t2 = newT();

如上写法是构造了3次(2次构造,一次拷贝),析构了3次
首先创建t2对象,然后newT函数中右创建一个t对象,然后将这个对象拷贝给一个匿名对象,再将newT中的t对象析构,然后将这个对象赋值给外面的t2对象,而此时的匿名对象被析构,析构完之后,当函数退出,t2对象也被析构

#include "iostream"
using namespace std;

class T {
private:
    int a;
public:
    T(int a ) {
        this->a = a;
        cout << "构造函数被调用" << endl;
    }
    T(const T & t) {
        this->a = t.a + 1;
        cout << "拷贝构造函数被调用" << endl;
    }
    ~T() {
        cout << this->a << endl;
        cout << "析构函数被调用" << endl;
    }
};

T newT() {
    T t(1);
    return t;
}

void test() {
    T t(3);
    t = newT();
}

int main() {
    test();
    system("pause");
    return 0;
}

最后得出的结论是,构造了多少次,就必须析构多少次。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值