本篇文章的读者是初学者,旨在帮助他们了解面向对象,同时也检验自己的水平,从而共同提高代码水平和效率,共勉之。
本文为读者详细介绍了构造函数和析构函数的执行顺序。
构造函数和析构函数
class A {
public:
A(){
cout << this << "default cosntructor" << endl;
}
A(int n, int m) : n(n), m(m), arr(nullptr), size(nullptr), offset(nullptr){
cout << "A(int) constructor" << endl;
}
A(int *size, int *offset) : size(size), offset(offset){
arr = new int[*size];
arr += *offset;
cout << "A(int *size) constructor" << endl;
}
~A(){
cout << this << " destructor" << endl;
if(arr == nullptr) return;
arr -= *offset;
delete[] arr;
}
int *arr, *size, *offset;
int n, m;
};
void main(){
A a(3 ,4);
A b(&a.n, &a.m);
cout << "&a : " << &a << " &b :" << &b << endl;
return;
}
执行结果:
构造
对象 a
的构造过程:
- 对象
a
被创建,调用参数构造函数- 在构造函数
A(int n, int m)
中输出 “A(int) constructor” 消息。 - 初始化
a.n
和a.m
成员。
- 在构造函数
对象 b
的构造过程:
- 对象
b
被创建,调用参数构造函数- 在构造函数
A(int *size, int *offset)
中输出 “A(int *size) constructor” 消息。 - 动态分配内存并初始化
b.arr
,设置b.size
和b.offset
成员。
- 在构造函数
总结:
- 对象
a
的构造使用的是A(int n, int m)
构造函数。 - 对象
b
的构造使用的是A(int *size, int *offset)
构造函数。
虽然两个对象都是通过参数构造函数创建的,但它们使用的构造函数是不同的。在 C++ 中,构造函数的选择取决于对象的初始化方式。在这里,a
使用的是直接传递两个整数的方式,而 b
使用的是传递指针的方式。
析构
对象 b
的析构过程:
- 对象
b
的析构函数被调用- 在析构函数
~A()
中输出 “destructor” 消息。 - 检查
b.arr
是否为nullptr
,然后释放动态分配的内存。
- 在析构函数
对象 a
的析构过程:
- 对象
a
的析构函数被调用- 在析构函数
~A()
中输出 “destructor” 消息。 - 检查
a.arr
是否为nullptr
,然后释放动态分配的内存。
- 在析构函数
总结:
-
析构函数的调用顺序与对象的销毁顺序相反。
-
在
main
函数结束时,先销毁对象b
,再销毁对象a
。特殊情况
在一些情况下,编译器会进行优化,避免产生不必要的拷贝构造函数调用。如果启用了返回值优化,会影响对象的创建和析构的顺序。
如果关闭了返回值优化,对象的拷贝构造函数和析构函数可能会更明显地反映在输出中。
在启用返回值优化的情况下,编译器可能会在不创建中间对象的情况下直接构造目标对象,因此看起来会跳过拷贝构造函数的调用。
有Linux中的g++编译器,输入下面命令可以关闭返回值优化:
g++ -fno-elide-constructors 名称.cpp
/*************************************************************************
> File Name: 3.cpp
> Author:
> Mail:
> Created Time: Tue Oct 24 21:21:35 2023
************************************************************************/
#include<iostream>
using namespace std;
正常应该是先有参,后拷贝,再拷贝到a,
class A {
public:
A() {
cout << this << " :无参" << endl;
}
A(int m){
cout << this << ": 有参 " << endl;
}
A(const A &a){
cout << this << ":拷贝" << endl;
}
~A() {
cout << this << "析构" << endl;
}
};
A fun(){
A temp(3);
return temp;
}
int main(){
A a = fun();
cout << "a :" << &a << endl;
return 0;
};
- 第一行:
0x7ffd14018767: 有参
,表示在fun
函数内创建了一个带有参数3
的A
对象,构造函数被调用。 - 第二行:
0x7ffd14018797:拷贝
,表示在fun
函数中,返回了一个对象,然后在main
函数中调用了拷贝构造函数,用这个返回的对象初始化了一个新的对象。 - 第三行:
0x7ffd14018767析构
,表示在fun
函数内创建的对象被销毁,调用了析构函数。 - 第四行:
0x7ffd14018796:拷贝
,表示在main
函数中,对象a
通过拷贝构造函数再次被复制到一个新的对象。 - 第五行:
0x7ffd14018797析构
,表示在fun
函数中创建的返回对象被销毁,调用了析构函数。 - 第六行:
a :0x7ffd14018796
,表示对象a
的地址。
,表示在main
函数中,对象a
通过拷贝构造函数再次被复制到一个新的对象。 - 第五行:
0x7ffd14018797析构
,表示在fun
函数中创建的返回对象被销毁,调用了析构函数。 - 第六行:
a :0x7ffd14018796
,表示对象a
的地址。 - 第七行:
0x7ffd14018796析构
,表示在main
函数中创建的对象被销毁,调用了析构函数