构造、析构、拷贝构造及赋值运算符重载——知识小结
// (1)大部分的类都需要自己写构造函数 (2)只有像MyQueue这样的类不需要显示构造函数
// 构造函数主要完成初始化工作 (3)每个类最好都要提供 默认构造函数(无需传参)。
// 初始化和清理
//
// 析构函数主要完成清理工作 (1)一些类需要显示写析构函数。比如:Stack\Queue....; (2)一些类不需要显示写析构函数。a\ 比如Date这样类,没有资源需要清理。
// b\ 比如MyQueue这样的类也可以不写,默认生成的就可以了。
// (3)析构的顺序:先定义的,后析构; 后定义的,先析构。
//
//
// 拷贝构造是使用同类对象初始化创建对象
// 6个默认成员函数 拷贝复制 (1)一些类需要显示写拷贝和赋值。比如:Stack\Queue....
// (2)一些类不需要显示写拷贝和赋值。A、比如像Date这样的类,默认生成就会完成值拷贝或浅拷贝
// B、比如MyQueue这样的类,默认生成就会调用他的自定义类型成员 Stack的拷贝和赋值。
// 赋值重载主要是把一个对象赋值给另一个对象
//
//
//
// 取地址重载 主要是普通对象和 const对象取地址,这两个很少会自己实现
//
//
//
// 构造函数 析构函数 拷贝构造函数 赋值运算符重载
//
// Date类 √ × × ×
//
//
// Stack类 √ √ √ √
//
//
// MyQueue类 × × × ×
1、存储在不同区域对象的初始化和析构的顺序
//函数栈帧和栈区(内存)内对象都要符合后进先出,也就是后定义先销毁/析构。
//(1)局部的对象(在栈区内)的析构顺序(先定义,后析构;后定义,先析构)
//(2)全局的对象(在静态区)在调用main函数之前就初始化了
//(3)静态的对象(在静态区)在首次调用的时候进行初始化(后面就不再进行初始化了)[同类型的静态变量,也遵循 先定义,后析构;后定义,先析构 ]
//(4)全局的对象和静态的对象都是在工程结束时才进行析构的。(所以最后析构)
#include <iostream>
using namespace std;
class A
{
public:
A(int a=0) //A(this,int a=0)
{
this->_a = a;
cout<< "A(int a=0)->" << _a << endl;
}
~A() // ~A(this)
{
cout<< "~A()->" << this->_a << endl;
}
private:
int _a;
};
A aa3(3); // 全局的对象(在静态区)在调用main函数之前就初始化了
void Func()
{
static A aa0(0); // 静态的对象(在静态区)在首次调用的时候进行初始化(后面就不再进行初始化了)
A aa1(1); // A aa1(&aa1,1);
A aa2(2);
static A aa4(4);
}
int main()
{
Func();
Func();
return 0;
}
2、传引用传参和传引用返回(拷贝构造函数)
2.1 传引用传参
class A
{
public:
//构造函数
A(int a)
{
_a = a;
cout<< "A(int a)->" << _a << endl;
}
//拷贝构造函数
A(const A& a)
{
_a = a._a;
cout << "A(const A& a)->" << _a << endl;
}
//析构函数
~A()
{
cout<< "~A()->" << _a << endl;
}
private:
int _a;
};
void Func1(A a)
{
cout<< "Func1" << endl;
}
void Func2(A& a)
{
cout << "Func2" << endl;
}
int main()
{
A a1(1);
//Func1(a1);
Func2(a1); //结论:针对于 自定义类型的对象而言,传引用传参比传值传参更具有优势,不需要拷贝构造,提高了效率。
// 对于内置类型变量而言,传值传参是对变量的临时拷贝,而传引用传参从底层分析也是开辟了四个字节的地址(创建指针)。
return 0;
}
2.2 传引用返回
class A
{
public:
//构造函数
A(int a)
{
_a = a;
cout << "A(int a)->" << _a << endl;
}
//拷贝构造函数
A(const A& a)
{
_a = a._a;
cout << "A(const A& a)->" << _a << endl;
}
//析构函数
~A()
{
cout << "~A()->" << _a << endl;
}
private:
int _a;
};
A Func3()
{
A a3(3);
return a3; //传值返回,返回的是a3的拷贝aa3 ,aa3在Func3()销毁之前还要析构。
}
A& Func4()
{
static A a4(4);
return a4; //传引用返回,返回的是a4的别名aa4。{需要注意的是,如果a4出了Func4()的作用域就销毁了,那么引用返回是有问题的}
//相比于传值返回,传引用返回不需要额外拷贝一次对象,也不需要再析构一次拷贝的对象。
}
int main()
{
Func3();
cout << endl;
Func4();
return 0;
}