一.构造函数
我们为什么需要构造函数?
我们需要多个对象且对象的各个属性都一样时,用构造函数可以在实例化每一个对象的时可以给每个对象都赋初值,这样可以简化工作。但是大家可以想想为什么不在定义属性的时候就赋值呢?这是因为啊,类其实是没有占内存空间的,从这个角度看,给一个没有内存空间的数赋值就不太可能了。
1.无参构造函数
C++编译器在实例一个对象,都执行了一次无参构造函数,这个无参构造函数是编译器自动提供的,但是无参构造函数里面没有写什么东西,所以我们在实例化一个对象是看不出来的。构造函数名字和类名相同,且没有返回值。
下面我们看看无参构造函数的具体实现
无参构造函数 类名()
Box(){
cout<<"Box()"<<endl;//这个语句为了验证构造函数的存在
}
下面我们验证一下,无参构造函数是否被执行到
#include<iostream>
using namespace std;
class Box{//类是没有存储空间的,只有实列化的对象才有存储空间
public://这就是为什么我们在类里面不能初始化
Box(){//从而引入了构造函数
cout<<"Box()"<<endl;//构造函数系统会默认生成,但必须没有写构造函数
}//默认的构造函数记得写,不然容易出问题
private:
double _x;
double _y;
double _z;
};
int main(){
Box box1,box2,box[3];
return 0;
}
Box()//实例化了5个BOX类的对象
Box()//每实例一次,构造函数被调用一次
Box()
Box()
Box()
当然构造函数主要的作用就是初始化数据
Box(){
_x=10;_y=20;_z=30;//每执行构造函数就会初始化
cout<<"Box()"<<endl; }
这样我们就能给每一个对象进行初始化,但是大家可能会有问题,在现实生活中哪有这么多一模一样的对象,所以无参构造函数肯定不能满足我们现实的生活。我们引入了有参构造函数。
2.有参构造函数
和无参构造函数一样,函数名和类名相同并且没有返回值,不同的是多了参数。
有参构造函数: 类名(数据类型 参数1 ,数据类型 参数2...)
有参构造和无参构造可以同时写出来的,在C语言里函数名是不能相同的,但是在C++中是允许的,这个便是函数的重载。
Box(double x,double y,double z){
_x=x;_y=y;_z=z;
}
Box box3(10,20,30);
不同于无参构造函数,有参构造函数实例化一个对象的时候必须传参,这样就可以为每一个赋不同的值了。
如果我们没有使用构造函数候是怎么进行赋值的,是用set函数来一个一个赋值,或者据点符号来赋值。
bool set_age(int age){
if(age<0||age>200){
cout<<"error age"<<endl;
return false;
}
_age=age;
return true;
}
通过set函数
t._age=34;
t._sex='m';
通过据点符号
明显看出构造函数的优点。
3.构造函数列表初始化
格式 : 类名(参数类别):初始化化对象(值)
public:
Box(int x,int y,int z):_x(x),_y(y),_z(z)//初始化_x,_y,_z
{
// _x=x;//这些叫做赋值,而不叫初始化
// _y=y;
// _z=z;
}
private:
int _x;
int _y;
int _z;
在构造函数里面执行的代码可不是初始化,而是进行了赋值操作。从这里看来好像列表初始化有点鸡肋,但其实不然,下面举出他的作用。
1.如果在类里面存在着引用,但是引用又必须初始化。
public:
Box():p(_x)//P(10)不能这么写,引用不能指向常量 int &p=10;
{
cout<<"Box()" <<endl;
}
Box(int x,int y,int z):_x(x),_y(y),_z(z),p(_x)
{
//p(_x)想这么写,必须先给_x进行初始化
}
private:
int _x; int _y; int _z;
int &p;//定义一个引用,引用在定义的时候必须初始化
在最新的版本的C++里面,想给一个引用赋值,除了这么写,还有这样的操作
public:
Box()
{
p=_x;//这样也可以修改p的值
cout<<"Box()" <<endl;
}
Box(int x,int y,int z)
{
_x=x;_y=y;_z=z;
p=_x;//修改p的值
}
private:
int _x;int _y;
int _z; //为了能在定义的时候初始化成想要的数,用构造函数的列表初始化
int b=10;//引用又必须初始化
int &p=b; //不初始化语法错误,为了解决这俩个问题,
但是不建议这么写。
2.类里面有只读变量,const修饰的常量
private:
const int c;//只读变量必须初始化 ,并且是一次性赋值 ,不能改了,
// //就是说如果在这里初始化化了就不能更改了,改就错了
// const int c=0; //为了能在定义的时候初始化成想要的数,用构造函数的列表初始化
public:
Box():c(_x)
{
cout<<"Box()" <<endl;
}
3.类的嵌套定义
class Box2{
public:
Box2()
{
}
Box2(int x)
{
_x=x;
}
private:
int _x;
};
class Box{
public:
Box():_x(x),box(2)//初始化
{
}
Box(int x):_x(x),box(2)//初始化
{
}
private:
int _x;
Box2 box;//在一个类里面定义一个类
};
在工作中假设有3个写了3个类,将自己的写的类封装成头文件发送给对方,但是自己没有写无参构造函数,又写了有参构造函数,那么在对方的类里用我的类定义时会报错,如果我们在定义的时候初始化,可以避开无参构造函数。