c++类——构造函数

本文最后更新于:1 天前

(一)概念:

创建类的对象的时候,编译系统需要对象分配内存空间,完成数据成员的初始化工作并请求其他资源,此时,编译系统自动调用构造函数来完成这些工作。

因此,构造函数是在创建类的对象时使用,它的核心作用是初始化对象的数据成员分配内存

(二)原型和特点:

构造函数的原型为:**类名::类名(参数表):初始化列表 { 构造函数体 }

​ ——所有倾斜内容表示在构造函数中此内容可选,不是必要的。

​ ——参数表即为所有的传入形参

​ ——初始化列表结构为:数据成员名(某形参名),数据成员名(某形参名)...

​ ——构造函数体可执行相关操作可为cout<<某些信息,对数据成员的某些操作等等。

构造函数的特点:

  1. 名字与类名相同,允许设定参数,但是不允许设置返回值(包括void)。

  2. 构造函数是编译系统在实例化一个对象时自动执行的,不需要手动调用(当然也可以主动手动调用)。调用后会对对象的数据成员进行初始化。

    定义自己的无参构造函数实际上是有用构造函数

  3. 构造函数可以重载,但是对象的实例化只会使用其中的一个构造函数(参数类型和个数能够最佳匹配),且实例化后不会再次执行构造函数,另外,重载构造函数后不允许出现二义性情况。

    • 重载构造函数具有不同的参数表和相同的名称

    • 根据传参个数决定调用哪个构造函数

    • 创建对象时要传参数让编译器明确知道调用哪个构造函数

  4. 在未定义构造函数时,编译系统生成一个无用的默认构造函数,无用的默认构造函数不含参数,不做任何初始化工作

    一旦定义了自己的构造函数,系统不会自己生成无用的默认的无参构造函数,但是仍然可以自己指定系统生成无用默认无参构造函数。

(三)分类:

  1. 默认构造函数,又名缺省构造函数,分为有用和无用两种,是不需要显式指定实参的构造函数——即原型为无参构造函数。

  2. 初始化构造函数——有参数。

  3. 复制(拷贝构造函数(不显式指定时有默认的复制构造函数)。

  4. 转换构造函数

(四)基本用法:

1.默认构造函数:

形式:

  1. 类名() =default;”的形式或者不存在任何构造函数——指定无用默认构造函数。

  2. "类名(){ 函数体 }"的形式——指定有用默认构造函数

调用时,因默认构造参数不需要形参,直接声明类的对象即可(切记不要在后面跟“()”!)。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
using namespace std;
class Time
{
private:
int hour;
int minute;
int sec;
public:
//此时状态为无构造参数,编译系统自动生成无用构造参数
//Time() = default; 仅去掉本行注释仍为无用构造参数
//Time() {hour=0;minute=0;sec=0;} 仅去掉本行注释为有用构造参数,可对三个数初始化为0
//上两行注释不能同时去掉,否则产生二义性。
void set_time()
{
cin >> hour >> minute >> sec;
return;
}
void show_time()
{
cout << hour << ":" << minute << ":" << sec << endl;
}

};
int main()
{
Time t1; //不能加"()"
t1.set_time();
t1.show_time();
return 0;
}

2.带参构造函数:

形式:类名:构造函数名(参数表):初始化列表 { 构造函数体 }

如果数据成员中有数组,要在构造函数体中用语句对其进行赋值,不能用初始化列表进行初始化。

以其他类作为数据成员时,需要在初始化列表进行初始化。初始化列表需要首先调用成员类的构造函数,再初始化自身的数据成员。

通常带参构造函数需要重载。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
using namespace std;
class Time
{
private:
int hour;
int minute;
int sec;
public:
//Time() = default;
Time() { hour = minute = sec = 0; }
Time(int i1, int i2, int i3) :hour(i1), minute(i2), sec(i3) {}//初始化列表方法
//Time(int i1, int i2, int i3) { hour = i1; minute = i2; sec = i3; }//构造函数体方法
Time(int h) :hour(h) { minute = sec = 0; }//重载构造函数1,实际上是转换构造函数
Time(int h, int m) :hour(h), minute(m) { sec = 0; }//重载构造函数2
//Time(int i1=0,int i2=0,int i3=0) :hour(i1), minute(i2), sec(i3) {}//含默认参数的构造函数,但要注意如果三个数均含默认参数,则会导致与默认构造参数产生二义性,只能保留一个。
void set_time()
{
cin >> hour >> minute >> sec;
return;
}
void show_time()
{
cout << hour << ":" << minute << ":" << sec << endl;
}

};
int main()
{
Time t1(1,2,3);
//Time t2;
//Time t3(1,2);
//Time t4(1);
t1.set_time();
t1.show_time();
return 0;
}

3.复制(拷贝)构造函数:

此内容较多,单开一篇博客,详见c++类——复制构造函数

4.转换构造函数:

形式:类名:构造函数名(单一参数):初始化列表 { 构造函数体 }

转换构造函数用于将其他类型的变量,隐式转换为本类对象。

传入的单一参数不能是本类的const引用,否则为复制构造函数。

转换构造函数可以与运算符重载配合使用(运算符重载详见c++类——运算符重载)。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
using namespace std;
class Time
{
private:
int hour;
int minute;
int sec;
public:
//Time() = default;
Time() { hour = minute = sec = 0; }
Time(int i1, int i2, int i3) :hour(i1), minute(i2), sec(i3) {}
Time(int h) :hour(h) { minute = sec = 0; }//转换构造函数

void set_time()
{
cin >> hour >> minute >> sec;
return;
}
void show_time()
{
cout << hour << ":" << minute << ":" << sec << endl;
}
Time operator+(const Time& temp)
{
return Time(this->hour + temp.hour, this->minute + temp.minute, this->sec + temp.sec);
}
};
int main()
{
Time t1=4; //此处4先被编译器用转换构造函数隐式转换为Time类的匿名变量,再复制给t1(调用了默认复制函数和转换构造函数)。
t1.show_time();
t1 = t1 + 5; //此处发生的是5先被编译器用转换构造函数隐式转换为Time类的匿名变量,再和t1通过运算符重载的函数进行相加。
t1.show_time();
return 0;
}

附:关键字explicit:

因为隐式类型转换往往会导致工程中出现一些奇奇怪怪的bug,所以,c++中定义了关键字explicit来杜绝转换构造函数的隐式类型转换。

关键字explicit只能用于修饰转换构造函数(也就是只含一个参数的类构造函数)或参数表中仅有一个没有默认参数的带参构造函数(等效于转换构造函数),其作用是表明该转换构造函数是显式的,而不是隐式的。

如果想指定默认情况为隐式的声明,可在前面指定关键字implicit。(不常用)

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
using namespace std;
class Time
{
private:
int hour;
int minute;
int sec;
public:
//Time() = default;
Time() { hour = minute = sec = 0; }
Time(int i1, int i2, int i3) :hour(i1), minute(i2), sec(i3) {}
explicit Time(int h) :hour(h) { minute = sec = 0; }//转换构造函数

void set_time()
{
cin >> hour >> minute >> sec;
return;
}
void show_time()
{
cout << hour << ":" << minute << ":" << sec << endl;
}
Time operator+(const Time& temp)
{
return Time(this->hour + temp.hour, this->minute + temp.minute, this->sec + temp.sec);
}
};
int main()
{
Time t1= static_cast<Time>(4);//必须显式指定,不会隐式转换。
//t1.set_time();
t1.show_time();
t1 = t1 + 5;// 不会发生隐式转换,运算符重载函数发生错误。
t1.show_time();
return 0;
}

c++类——构造函数
https://github.com/xiaohei07/xiaohei07.github.io/2023/03/16/c++类——构造函数/
作者
07xiaohei
发布于
2023年3月16日
许可协议