C++构造函数与析构函数

C++构造函数与析构函数

1.构造函数——初始化成员的函数

A.构造函数的形式

  1. 构造函数没有返回值(连void都没有)
  2. 构造函数与类名同名
  3. 构造函数可以重载
  4. C++中,构造函数不能相互调用来构造同一个函数

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

B.构造函数的调用——创建对象(分配空间),然后调用构造

a.初始化时调用

//隐式调用
class_name obj;     //隐式调用无参构造函数
class_name obj(参数列表);   //隐式调用有参构造

注意,隐式调用无参构造,对象名后没有括号,如果有 calss_name obj();这样就变成了一个函数声明

//显式调用
class_name obj = class_name();
class_name obj = class_name(参数列表);

初始化时显式调用分两种情况(与编译器有关):
第一种,与隐式调用一样。
第二种:生成一个临时变量,然后将临时变量的值赋给声明的对象

/*我使用的时VS2017*/
class A {
private:
    int a;
public:
    A(int a = 0);
    void show() const;
};

A::A(int a) {
    this->a = a;
    cout << this << "调用构造" << endl;
}

void A::show() const {
    cout << "a = " << a << endl;
}


int main() {

    A obj = A(1);
    obj.show();

    return 0;
}

输出:

00AFFED8调用构造
a = 1

可见,这样的环境下初始化显式调用与隐式调用没有区别

C++11,可以使用{}初始化

class_name obj{参数列表};

上述初始化有一个条件,参数列表必须与一个构造函数对应

b.改变一个对象的值

调用构造,生成一个临时变量,然后将临时变量的值赋给声明的对象

obj = class_name(); //调用无参构造,改变obj的值

这里与初始化时不同,这里一定会生成临时变量调用构造

int main() {

    A obj;      //第一次调用构造
    obj.show();
    obj = A(3); //第二次调用构造,生成临时变量
    obj.show();
    return 0;
}

输出:

00EFFEB4调用构造
a = 0
00EFFDE8调用构造
a = 3

c.注意,C++构造函数无法相互调用(与JAVA的区别)

除了初始化的时候情况不确定,其他情况下c++调用构造时,都会产生临时对象

class A {
private:
    int a;
public:
    A(int a);
    A();
};

A::A(int a) {
    this->a = a;
    cout << this << "调用有参构造" << endl;
}

A::A(){
    outFile << this << "调用无参构造" << endl;
    A(0);
}

上述代码的目的,就是想要在无参构造时,默认的调用有参构造进行初始化,然而,事与愿违

输出:

00D7FBA4调用无参构造
00D7F9F8调用有参构造

可见,两次调用构造的对象不一样,说明不是初始化一个对象,C++可以用默认参数解决这个问题

C.创建对象,调用系统默认生成复制构造函数构造函数的情况

复制构造函数 classname(classname &object);

在初始化时,直接进行赋值 classname obj = anotherobj;这里实际这样调用classname(anotherobj)

对象初始化时,直接将一个已有对象的值赋给它,将会调用系统生成的复制构造函数

    A obj1;
    A obj2 = obj1;

输出:

    00CFFC0C调用无参构造

2.构造函数的调用——对象空间释放(定位new分配的空间除外),就要调用

A.析构函数形式

  1. 没有返回值
  2. 没有形参
  3. 不可重载
  4. 函数名——~class_name()

B.析构函数的调用——空间释放时系统自动调用

只要是对象空间(我们声明的、系统临时的),一旦释放,就要调用析构

例子: A::A(int a) { this->a = a; cout << this << "调用构造" << endl; }

A::~A() {

cout << this << "调用析构" << endl;
}

我我进行如下调用: int main(){

    A obj(3);
    obj = A(3);
    return 0;
}

输出:

0035FDE4调用构造        //obj调用构造
0035FD18调用构造        //临时变量调用构造
0035FD18调用析构        //临时变量空间释放
0035FDE4调用析构        //main()执行完毕,obj释放

C.注意:

临时变量包括了函数的返回值,也被存储在一个临时的变量,这个临时变量释放时,也会调用析构函数,我的另一篇博客会说到

D.通过定位new分配的对象,要在buffer释放前显式调用析构

int main(){

    char *buffer = new char[BUF];//创建一个用于定位new的区域

    A *pa = new(buffer)A();     //使用定位new
    ...         //一些操作

    pa->~A();       //下一步要释放定位new使用的buffer区域
                    //如果这里不显式调用,则不会调用析构
    delete[] buffer;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值