构造函数
1.函数名与类名要相同
2.无返回值、
3.无参数构造函数和全缺省构造函数,我们认为这两种是默认构造函数。
4.构造函数可以函数重载。
我们默认构造函数可以直接定义在类里面,定义在类里面编译的时候,如果编译器允许,会把它当成是个内联函数来处理,这样省去了一部分的空间。
(1)一般情况下,构造函数都需要我们自己写;
(2)以下两种情况可以不需要,
a.内置类型成员(int,char.......)都有缺省值,且初始化符合我们的要求
b.全是自定义类型的构造,且这些类型都定义默认构造,就比如用栈来实现队列。
#include<iostream>
using namespace std;
class Date
{
public:
Date(int year = 2000, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
这里的Date就是简单的实现一个默认构造,我们在如何用?编译器会自动调用。
这里的tmp1我没有给它值,编译器会自动的调用默认构造给他初始化,我们也可以直接给他我们想要初始化的值。
下面我们来认识一个特殊一点的构造函数——拷贝构造函数(这里讲的是浅拷贝)
拷贝构造函数是对类型对象的引用,常用const修饰。注意千万不能用传值,必须要用引用,否则会造成无穷递归(为什么?下面有讲解)。他的特征:
1.是构造函数的重载
2.有且仅有一个参数,且必须是类类型对象的引用。
class Date
{
public:
Date(int year = 2000, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date tmp1;
Date tmp2(2023, 5, 1);
Date tmp3(tmp2);
return 0;
}
为什么要是我们传值会产生无穷递归?
因为我们如果是对内置成员传值,是可以直接把值传过去的,也就是直接拷贝值过去,但c++中,我们在对类类型传值时,是要先去调用它的拷贝构造(这一步我们记作A),然后再把拷贝好的值给带回去,然后把值给我们的参数,
void fun(Date d)
{
}
int main()
{
Date tmp;
fun(tmp);
return 0;
}
就比如我们在用函数fun时,我们不是直接就进入到函数里,我们的第一步是先去调用Date的拷贝构造函数,将值拷贝给我们的d,也就是说我们是先进行了
Date d(tmp);
然后才是fun(Date d);
那么我们假如拷贝构造是个传值,
class Date
{
public:
Date(int year = 2000, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
Date(const Date d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date tmp1;
Date tmp2(tmp1);
return 0;
}
我们在要调用拷贝构造tmp2(tmp1)时,我们第一步要把实参的值拷贝给拷贝构造的形参d,那就要去调用我们的拷贝构造,调用我们的拷贝构造,我们此时的步骤相当于d(tmp1),然后就再一次要调用我们的拷贝构造,这时候是第二层拷贝构造,是第二次在使用拷贝构造,那么此时的拷贝构造里的参数的值就需要再次拷贝,此时拷贝构造的参数就需要我们再次进行把实参拷贝给形参,就又需要调用拷贝构造,然后我们又去调用拷贝构造,然后拷贝构造的形参值又是不确定,又需要把实参的值拷贝给形参,那就又需要调用拷贝构造,无穷无尽。