C++函数
一、构造函数
类名(形参表){}
1、构造函数:类的同名函数,没有返回值。
2、创建类型对象时会被自己调用(每创建一个类对象就会调用一次),对象整个生命周期中一定会被调用一次,也只能被调用一次。
3、构造函数主要用来负责成员变量的初始化,分配相关资源,设置对象的初始状态
4、构造函数可以被重载
二、析构函数
~类名(void){}
1、是特殊的成员函数。
2、析构函数会在销毁对象时自动调用,在对象整个生命周期内最多被调用一次。
3、析构函数负责释放在构造函数期间所获取的所有资源。
4、如果一个类没有实现析构函数,会在编译时自动生成一个具有析构函数功能的二进制指令,它负责释放编译器所能看到的资源(成员变量、类成员、父类成员),即缺省构造(唯一的作用就是避免系统错误)。
5、析构函数因为没有参数,所以不可以被重载
6、当类成员中有指针成员时,必须实现析构函数
三、拷贝构造
类名(类&){}
1、拷贝构造又称复制构造,是一种特殊的构造函数,它是使用一个现有的旧对象构造一个新对象时调用的函数,只有一个引用型的参数(对象本身)。
2、当用一个对象给另一个对象初始化时,会调用隐藏的拷贝构造函数(自带的)
3、当类成员中有指针成员,浅拷贝只拷贝指针变量的值,而深拷贝是拷贝指针变量所指向的目标。
4、当类成员中有指针成员,且指针指向堆内存资源,浅拷贝会导致该资源被释放两次,此时默认的拷贝构造(浅拷贝)就无法完成任务,需要自己手动实现拷贝构造(深拷贝)。
注意:
什么情况下会调用拷贝构造:
①使用旧对象给新对象赋值时(初始化)
`User user1 = user;
//User user1; user1=user; 此时是赋值,不是初始化,不会调用拷贝构造
②使用对象当作函数的参数,当调用函数时就会一起调用拷贝构造。
四、赋值构造
void operator=(const 类&){}
1、当一类旧对象给另一个类旧对象赋值时,就会调用赋值构造。(对象=对象)
2、编译器会生成一个缺省的赋值构造,负责把一个对象的内存拷贝给另一个对象(浅拷贝)。
3、当需要深拷贝时需要自己手动实现,也就是拷贝构造与赋值构造需要同时实现。
关于拷贝构造、赋值构造的建议
1、缺省的拷贝构造、赋值构造函数不光会拷贝本类的数据,也会调用成员类对象和父类的拷贝构造和赋值构造,而不是单纯的按字节复制,因此尽量少用指针成员。
2、在函数参数中尽量使用类指针或引用来当参数(不要直接使用类对象),减少调用拷贝构造和赋值构造的机会,也可以降低数据传递的开销。
3、如果由于特殊原因无法实现完整的拷贝构造、赋值构造,建议将它们私有化,防止误用。
4、一旦为一个实现了拷贝构造,那么也一定要实现赋值构造。
实现string类的四个隐藏函数:
- 构造函数
- 析构函数
- 拷贝构造
- 赋值构造`
#include <iostream>
#include <cstring>
using namespace std;
class String
{
char* str;
public:
//构造
String(const char* str="")
{
this->str= new char[strlen(str)+1];
strcpy(this->str,str);
}
//拷贝构造
String(const String& that)
{
str=new char[strlen(that.str)+1];
strcpy(str,that.str);
}
//析构
~String(void)
{
delete[] str;
}
//赋值构造
void operator=(const String& that)
{
if(this!=&that)
{
//防止内存泄露
delete[] str;
str=new char[strlen(that.str)+1];
strcpy(str,that.str);
}
}
void show(void)
{
cout << str <<endl;
}
};
int main()
{
const String st("haha");
String st2=st;
String st3;
st3 = st;
st2.show();
st3.show();
}