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

一,构造函数析构函数

调用顺序

我们先来看下面的代码:

cpp 复制代码
#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赋予初始值,那么他们析构构建顺序又是怎样的呢

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

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

全局变量出现

cpp 复制代码
#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循环,函数返回值等上,看代码:

cpp 复制代码
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,那就是还未创建。

二,拷贝构造

cpp 复制代码
#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存储这个学生类的地址空间,这样就可以正常返回了,也就出现了两个拷贝构造函数调用。

相关推荐
yyds_yyd_100862 分钟前
3731. 找出缺失的元素(2026.08.04)
c++·leetcode
Chen—LSN10 分钟前
C语言——深度理解指针(5)
c语言·数据结构·算法·排序算法
呱呱巨基17 分钟前
CMake基础
linux·c++·笔记·学习
程序员-Benothing1 小时前
如何实现高并发系统订单30分钟自动关闭?
开发语言·c#·wpf
佳児素花痴╮2 小时前
树的基础知识与查找排序算法
数据结构·算法
郝学胜-神的一滴2 小时前
Python 高级编程 026:内置数据结构之骈文纵论
开发语言·数据结构·python·程序人生·软件工程
lueluelue479 小时前
LeetCode:链表
算法·leetcode·链表
隐积10 小时前
3.1.7.Qt容器大家族(3):QVariant——万能盒子
开发语言·qt
橘子汽水16812 小时前
Leetcode 23,543合并K个升序链表,二叉树的直径
算法·leetcode·链表
huameinan狮子12 小时前
Adaboost算法原理与计算实例
算法