引入:构造函数的由来
对于以下Date类:
class Date
{
public:void Init(int year, int month, int day){year = year;_month = month;_day = day;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private:int _year;int _month;int _day;
};int main()
{//创建一个d1 并且初始化Date d1;d1.Init(2022, 7, 5);d1.Print();//创建一个d2 并且初始化Date d2;d2.Init(2022, 7, 6);d2.Print();return 0;
}
疑问:创建一个对象就得初始化一次, 未免有点麻烦,那能否在对象创建时,就将信息设置进去呢?所以就有了构造函数!
一:构造函数的概念
构造函数 是特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是构造函数的主要任
务 并不是开空间创建对象,而是初始化对象 。
其特征如下:
1. 函数名与类名相同
2. 无返回值(void都不用写)
3. 对象实例化时编译器 自动调用 对应的构造函数
4. 构造函数可以重载(可以多个构造函数)
二:构造函数的分类
1:无参构造函数(全缺省,无参)->无参构造函数又叫默认构造函数
2:含参构造函数
三:构造函数的使用
①:无参构造函数
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;class Date
{
public:// 1.无参构造函数Date(){_year = 1;_month = 1;_day = 1;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}private:int _year;int _month;int _day;
};int main()
{Date d1; // 调用无参构造函数return 0;
}
结果:
②:含参构造函数
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;class Date
{
public:// 2.带参构造函数Date(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}private:int _year;int _month;int _day;
};int main()
{Date d1(1,1,1); // 调用无参构造函数d1.Print();return 0;
}
结果:
③:全缺省构造函数
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;class Date
{
public:// 2.带参构造函数Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}private:int _year;int _month;int _day;
};int main()
{Date d1;d1.Print();Date d2(1, 1, 1); // 调用无参构造函数d2.Print();return 0;
}
结果:
①②③点的总结:
三种构造函数都可以单独使用,但是需要注意的是,无参构造函数不管是全缺省还是真的没有参数,在用的时候,都不能带括号,否则会变成函数的声明(类似 int Add( ) )
int main()
{Date d1;//正确Date d2();//错误,成了函数声明return 0;
}
④:多个构造函数
class Date {
public://无参构造函数 Date() {_year = 1;_month = 1;_day = 1;}//带参构造函数 Date(int year, int month, int day) {_year = year;_month = month;_day = day;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}private:int _year;int _month;int _day;
};int main(void)
{Date d1;// 调用无参构造函数d1.Print();Date d2(2024, 10, 14);// 调用带参构造函数d2.Print();return 0;
}
结果:
④的总结:
构造函数正如其特征中的第4点,可以重载,但是默认构造函数(全缺省构造函数和无参构造函数)只能存在一个,二者语法上可以共存,但是却因为二义性不能共存
二义性代码展示:
class Date {
public:Date() {_year = 1;_month = 1;_day = 1;}Date(int year = 2024, int month = 10, int day = 14) {_year = year;_month = month;_day = day;}private:int _year;int _month;int _day;
};int main(void)
{//无参,那到底是走无参,还是全缺省???Date d1;return 0;
}
结果:
总结:
强烈推荐全缺省的构造函数,因为真的很好用!
代码如下:
#include <iostream>class Date {public:/* 全缺省 */Date(int year = 0, int month = 1, int day = 1) {_year = year;_month = month;_day = day;}void Print() {printf("%d-%d-%d\n", _year, _month, _day);} private:int _year;int _month;int _day;
};int main(void)
{Date d1; // 不传,就是缺省值Date d2(2024, 10, 14);Date d3(2024);Date d4(2024, 10);d1.Print(); // 0-1-1d2.Print(); // 2024-10-14d3.Print(); // 2024-1-1d4.Print(); // 2024-10-1return 0;
}
四:C++编译器自动生成的无参默认构造函数
Q:如果我们不在类中,显式的写构造函数呢,系统会做什么吗?
A:会的,C++编译器会自动生成的无参默认构造函数
那C++编译器生成的构造函数,会对成员变量做什么呢?
无构造函数代码:
class Date
{public:private:int _year;int _month;int _day;
};int main(void)
{//C++编译器生成的是无参构造函数//所以也不能带(),否则成为函数声明Date d1;return 0;
}
结果:
发现其还是随机值?那岂不是什么都没做?
解释:
C++ 把类型分成内置类型 ( 基本类型 ) 和自定义类型。内置类型就是语言提供的数据类型,如:int/char... ,自定义类型就是我们使用 class/struct/union 等自己定义的类型,看看下面的程序,就会发现编译器生成默认的构造函数会对其内置类型的变量不作初始化,对其自定类型成员_t 调用的它的默认构造函数
①:自身类中没有显式定义构造函数,但成员变量中的自定义变量有默认构造函数(无参)
class Time
{
public:Time(){cout << "Time()" << endl;//打印了Time(),就代表这个构造函数被调用了_hour = 0;_minute = 0;_second = 0;}
private:int _hour;int _minute;int _second;
};
class Date
{
private:// 基本类型(内置类型)int _year;int _month;int _day;// 自定义类型Time _t;
};
int main()
{Date d;return 0;
}
结果:
解释:正如前文所说, 会对其内置类型的变量不作初始化,对其自定类型成员_t调用的它的默认构造函数
②:自身类中没有显式定义构造函数,但成员变量中的自定义变量有默认构造函数(全缺省)
class Time
{
public:Time(int hour = 8, int minute = 24, int sconde = 5){cout << "Time()" << endl;//打印了Time(),就代表这个构造函数被调用了_hour = hour;_minute = minute;_second = sconde;}
private:int _hour;int _minute;int _second;
};
class Date
{
private:// 基本类型(内置类型)int _year;int _month;int _day;// 自定义类型Time _t;
};
int main()
{Date d;return 0;
}
结果:
③:自身类中没有显式定义构造函数,但成员变量中的自定义变量有含参的构造函数(非默认)
class Time
{
public:Time(int hour, int minute, int seconf){cout << "Time()" << endl;_hour = 0;_minute = 0;_second = 0;}
private:int _hour;int _minute;int _second;
};
class Date
{
private:// 基本类型(内置类型)int _year;int _month;int _day;// 自定义类型Time _t;
};
int main()
{Date d;return 0;
}
结果:
④:自身类中没有显式定义构造函数,且成员变量中的自定义变量也没有构造函数
class Time
{
public://无构造函数
private:int _hour;int _minute;int _second;
};
class Date
{private:// 基本类型(内置类型)int _year;int _month;int _day;// 自定义类型Time _t;
};
int main()
{Date d;return 0;
}
结果:
解释:都是随机值,但是可以看出,d的内置类型随机值是因为C++编译器生成的默认构造函数造成的,自定义类型_t 的成员变量也是随机值,这也是C++为Time类自动生成的默认构造函数造成的,都是随机值,但是这也是对类型的一种处理
补充:
C++11 中针对内置类型成员不初始化的缺陷,又打了补丁,即: 内置类型成员变量在 类中声明时可以给默认值 。
置类型成员变量在 类中声明时可以给默认值的 代码如下:
class Time
{
public:Time(){cout << "Time()" << endl;_hour = 0;_minute = 0;_second = 0;}private:int _hour;int _minute;int _second;
};class Date
{private:// 基本类型(内置类型)int _year = 2024;int _month = 10;int _day = 14;// 自定义类型Time _t;
};
int main()
{Date d;return 0;
}
结果:
总结:
C++ 编译器生成默认的构造函数会对其内置类型的变量不作初始化,对其自定类型成员_t 调用的它的默认构造函数(不写自动生成的默认构造函数,写的无参或全缺省),根据默认构造函数来初始化,且含参的构造函数会报错。