目录一、类的默认成员函数二、构造函数Date(形参列表)1、构造函数的函数名和返回值2、构造函数的调用3、构造函数的重载4、系统生成的默认构造函数5、系统生成的默认构造函数的作用6、
构造函数主要完成初始化对象,相当于C语言阶段写的Init函数。
默认构造函数:无参的构造函数或全缺省的构造函数,二者只能存在一个,同时存在类中,调用时会出现二义性。
构造函数的函数名和类名相同且无返回值
对象实例化时,编译器自动调用对应的构造函数且只调用一次
构造函数可以重载(多种初始化方式)注意:虽然全缺省和无参的构造函数构成重载,但是调用时存在二义性。
class Date
{
public:
//构造函数的重载
Date()
{
}
Date(int year,int month,int day)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;//创建并通过无参构造函数初始化对象时,无需加括号,不然变成了函数声明
Date d2(2022,9,23);
return 0;
}
如果我们在类中不写构造函数,C++编译器会在类中帮我们生成一个无参的构造函数。我们写了构造函数,那么系统将不会生成。
我们构造对象并调用构造函数时,初始化的数据是随机值:
系统生成默认构造函数对内置类型不处理,对自定义类型调用他的构造函数。
注意:下方代码中,Date类中的内置类型将会调用Date类中的构造函数;Date类中的Time _t将会调用Time类中的构造函数。
C++11中针对内置类型不处理初始化为随机值的问题,打了补丁:内置类型成员变量在类中声明可以给默认值,甚至可以给动态开辟的缺省值,缺点是不能判断空间是否开辟成功。
注意这里的默认值是缺省值,不是初始化。初始化是要等对象调用时才叫初始化。
class Date
{
private:
int _year=1;
int _month=2;
int _day=3;
int* arr = (int*)malloc(sizeof(int) * 5);
};
这个特性只能用于解决默认构造函数初始化为随机值的问题。这个特性不能解决对象的多种初始化方式(这也是构造函数支持重载的原因),构造函数该写还是得自己写。
Date(int year=1,int month=1,int day=1)//缺省值
:_year(year)//成员变量的定义
,_month(month)
,_day(day)
{}//成员变量的赋初值
总结:尽量使用使用初始化列表进行初始化,在类中尽量提供默认构造函数(最好是全缺省的默认构造函数)
class Date
{
public:
Date(int year=1,int month=1,int day=1)
:_year(year)
,_month(month)
,_day(day)
{}
private:
int _year;
int _month;
int _day;
};
int main()
{
//单参数的构造,构造+拷贝,编译器直接优化为构造C++98
Date d1 = 2022;
//临时对象具有常性,构造+拷贝,编译器不会优化
const Date& d2 = 2023;
//多参数的构造C++11
Date d3 = { 2022,10,16 };
return 0;
}
析构函数:与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。资源包括动态开辟的空间,文件的关闭等。相当于C语言阶段写的destroy函数。
析构函数的函数名是类名前加~,无参无返回值类型。
一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构函数不能重载
对象生命周期结束时,C++编译系统系统自动调用析构函数
对于编译器生成的默认析构函数,对自定义类型调用他的析构函数。对于内置类型,没有需要处理资源。
注意:Date类中的内置类型会调用Date类中的析构函数;Date类中的自定义类型Time _t会调用Time的析构函数。
1、拷贝构造函数是构造函数的重载
拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。
拷贝构造函数的函数名和构造函数相同,无返回值,在参数上和构造函数构成重载。
2、拷贝构造函数的参数
拷贝构造函数的参数只有一个并且是类类型对象的引用。如果使用传值传参的方式进行拷贝构造,在传值的过程中实参需要拷贝一份数据给形参,这个过程需要调用拷贝构造。形成层层传值引发对象的拷贝的递归(有递无归)调用。
3、若未显式定义,编译器会生成默认的拷贝构造函数
默认的构造函数对于内置类型按照字节拷贝。对于自定义类型则调用它的拷贝构造函数。
4、拷贝构造函数的深浅拷贝
通过默认的拷贝构造函数构造的对象,按字节完成拷贝。这种拷贝被称为浅拷贝(值拷贝)。
int main()
{
Date d1(2022,9,24);
Date d2(d1);
return 0;
}
对于内置类型,使用浅拷贝即可,系统默认生成的就可以做到,所以我们不用动手写拷贝构造函数。注意这里有d1,d2两个对象,当main函数生命周期结束时,这两个对象均会发生一次析构,d2先析构,d1后析构。(后定义的先销毁,类似栈的后进先出原则)
但是浅拷贝对于占用“资源”的成员变量时(例如成员变量中有动态开辟或fopen的资源),指针虽然复制了,但是所指向的内容却没有复制,析构时存在同一块空间被释放两次的问题。需要进行深拷贝。深拷贝的拷贝构造函数必须自己手动实现。
class Stack
{
public:
Stack(int capacity=100)//构造函数
{
_capacity = capacity;
_top = 0;
_arr = (int*)malloc(sizeof(int) * 5);
if (_arr == nullptr)
{
perror("malloc fail");
exit(-1);
}
}
//Stack(const Stack& st)//浅拷贝,栈这个类不能用浅拷贝
//{
// _capacity = st._capacity;
// _top = st._top;
// _arr = st._arr;
//}
Stack(const Stack& st)//深拷贝
{
_capacity = st._capacity;
_top = st._top;
_arr = (int*)malloc(sizeof(int) * st._top);
if (_arr == nullptr)
{
perror("malloc fail");
exit(-1);
}
memcpy(_arr, st._arr,sizeof(int)*st._top);
}
~Stack()//析构函数
{
_capacity = 0;
_top = 0;
free(_arr);
_arr = nullptr;
}
private:
int* _arr;
int _top;
int _capacity;
};
栈这个类因为成员变量中有动态开辟的空间,所以要用深拷贝。
5、拷贝构造函数调用场景
1、赋值运算符重载
只有赋值运算符是默认成员函数。
2、赋值运算符重载的注意事项
Date* operator&()
{
return this;
//return nullptr;
}
const Date* operator&()const
{
return this;
//return nullptr;
}
不用自己写,除非想让别人通过取地址操作符获取到特定值(自己在重载函数内部写)或屏蔽类地址。
以上就是详解C++中类的六大默认成员函数的详细内容,更多关于C++类成员函数的资料请关注编程网其它相关文章!
--结束END--
本文标题: 详解C++中类的六大默认成员函数
本文链接: https://lsjlt.com/news/169398.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-03-01
2024-03-01
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0