C++入门8 构造函数析构函数顺序|拷贝构造

一,构造函数析构函数

调用顺序

我们先来看下面的代码:

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring> 
using namespace std;
class student {
public:
    char my_name[20];
    int my_id;
    student(int a) {
        my_id = a;
        cout << "构造函数被调用" <<" 学生id为: "<<my_id <<endl;
    }
    ~student() {
        cout<< "析构函数被调用" << " 学生id为: " << my_id << endl;
    }
};

int main() {
    student a(10);
    student b(20);
    cout << endl;
    return 0;
}

这个代码简单的定义了一个学生类,初始化了构造函数和析构函数,a,b赋予初始值,那么他们析构构建顺序又是怎样的呢

可以看到,先定义的先调用构造函数,同时后调用析构函数,这是为什么呢

因为我们系统变量都是在栈区去定义的,我们的栈是一个先进后出的结构,所以导致了这样的情况出现。

全局变量出现

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring> 
using namespace std;
class student {
public:
    char my_name[20];
    int my_id;
    student(int a) {
        my_id = a;
        cout << "构造函数被调用" <<" 学生id为: "<<my_id <<endl;
    }
    ~student() {
        cout<< "析构函数被调用" << " 学生id为: " << my_id << endl;
    }
};

student max(100);
int main() {
    student a(10);
    student b(20);
    cout << endl;
    return 0;
}
student min(1);

这个代码的顺序又是如何呢,min变量又会不会参与我们的调用的,我们看看运行结果便知。

可以看到,min参与了调用,因为全局变量在预编译之后,编译之前便会全部初始化,与他的位置无关。

但因为min在主函数后面,所以打印等操作是不被允许的。

还有一件事,如果我们的全局变量和局部变量命名冲突了又该如何呢

我们遵循局部优先的原则,如果想使用全局变量,需要使用  ::全局域解析符

static

static是静态关键字,使用他可以是变量在需要销毁的时候保留,可以作用在for循环,函数返回值等上,看代码:

int main() {
    //student a(10);
    //student b(20);
    cout << endl;
    for (int i = 0; i < 10; i++)
    {
        static student a(10);
        
    }

    return 0;
}

难道就因为我们使用了static关键字,我们每次的循环都需要创建一变a吗。

编译器当然不会这么做,他只会在第一次循环创建,那么他是怎么知道这是第几次创建呢,

我们发现a下面赋值为一,这就是编译器的处理,这个位置叫做标记域,编译器如果发现标记域为一,那就是已经创建过的变量,如果为0,那就是还未创建。

二,拷贝构造

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring> 
using namespace std;

class student {
public:
    char my_name[20];
    int my_id;
    student(int a) {
        my_id = a;
        cout << "构造函数被调用" << " 学生id为: " << my_id << endl;
    }
    student() {
        my_id = 0;
        cout << "构造函数被调用" << " 学生id为: " << my_id << endl;
    }
    ~student() {
        cout << "析构函数被调用" << " 学生id为: " << my_id << endl;
    }
    student(const student& it) :my_id(it.my_id) {
        cout << "拷贝构造函数被调用" << endl;
    }
    void Setvalue(int c) {
        my_id = c;
    }
};

student func(student c) {
    c.Setvalue(10);
    return c;
}

int main() {
    student a(10);
    student b = func(a); // 使用func函数来创建b
    cout << endl;

    return 0;
}

这段代码,我们会输出什么,思考

为什么会有两个拷贝构造函数呢,原因是我们在函数中试图返回一个学生类,我们知道函数返回值存储在eax寄存器中,而这个寄存器大小很小,只有四个字节,我们的学生类远远超过四个字节,所以编译器就需要想办法了,他同样拷贝构造了一个一摸一样的学生类在主函数栈帧空间里,eax存储这个学生类的地址空间,这样就可以正常返回了,也就出现了两个拷贝构造函数调用。

最近更新

  1. TCP协议是安全的吗?

    2024-06-15 00:34:04       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-15 00:34:04       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-15 00:34:04       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-15 00:34:04       18 阅读

热门阅读

  1. 深入解析 Unix I/O 的五种模型

    2024-06-15 00:34:04       9 阅读
  2. mysql-线上常用运维sql-2

    2024-06-15 00:34:04       9 阅读
  3. ant-desigin-vue动态表头并填充数据

    2024-06-15 00:34:04       8 阅读
  4. DataCap 自定义 File 转换器

    2024-06-15 00:34:04       6 阅读