文章目录
- 一、类的6个默认成员函数
- 二、 构造函数
- 干嘛的?
- 语法定义
- 特性
- 综上总结
- 什么是默认构造函数?
- 三、析构函数
- 干嘛的 ?
- 语法定义
- 析构顺序
一、类的6个默认成员函数
如果一个类中什么成员都没有,简称为空类。空类中并不是真的什么都没有。任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。
默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。
二、 构造函数
干嘛的?
构造函数是特殊的成员函数 用来初始化对象 。
语法定义
1️⃣函数名和类名相同
2️⃣没有返回值(不需要写)
代码演示:
class Date
{
public:
//函数名与类名相同 没有返回值 不用写void
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;
d1.Print();
return 0;
}
3️⃣对象实例化时 编译器自动调用该函数,如果没有构造函数可调,会报错。
反汇编演示自动调用:
4️⃣构造函数可以重载(重载:函数名相同,参数不同)
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()
{
Date d1;
d1.Print();
Date d2(2024, 1, 27);
d2.Print();
return 0;
}
注意:无参的构造函数 和 全缺省的构造函数 可以同时存在类的定义里,但一般不这样写,因为调用会存在 歧义。
class Date
{
public:
//无参的构造函数
Date()
{
_year = 1;
_month = 1;
_day = 1;
}
//全缺省的构造函数
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()
{
Date d1;
Date d2(2024, 1, 27);
return 0;
}
比如会出现如下报错:
构造函数可以带参数、也可以不带参数
带参数的情况:实例化对象时,直接把参数跟在对象后面就可以。
无参数的情况:实例化对象时,不能跟空括号()在对象后面,原因是:改写法无法跟函数声明区分开。
实践中,更多的情况直接用全缺省的构造函数
特性
思考下面的日期类我们没提供构造函数的情况是否会被初始化?
class Date
{
public:
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
d1.Print();
}
1、构造函数 ,是默认成员函数,程序员不写,编译器会生成一个,但是自动生成的构造函数初始化出的成员变量没有默认值(具体根据成员变量的类型而定)。
tips:C++ 中 数据类型分为
内置类型(基本类型): int /char /doube/指针… 语言自身定义的类型
自定义类型: struct /class
C++98 规定 ,编译器自动生成的 构造函数 对于内置类型不做处理,自定义类型会去调用他的默认构造函数。
演示代码:
class A
{
public:
A()
{
cout << "A()" << endl;
_a = 0;
}
private:
int _a;
};
class Date
{
public:
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
// 内置类型 不做处理
int _year ;
int _month ;
int _day;
// 自定义类型 调默认构造
A _aa;
};
int main()
{
Date d1;
d1.Print();
}
C++11 委员会对这个语法进行打补丁,对于内置类型 在成员变量声明位置 可以给缺省值 ,编译器自动生成的构造函数就会用程序员给出的这个缺省值初始化成员变量。
class A
{
public:
A()
{
cout << "A()" << endl;
_a = 0;
}
private:
int _a;
};
class Date
{
public:
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
// C++11 内置类型 声明位置可以给缺省值
int _year =1;
int _month =1;
int _day;
// 自定义类型 调默认构造
A _aa;
};
int main()
{
Date d1;
d1.Print();
}
综上总结
编译器自动生成的构造函数 在进行对象实例化时 对成员变量的初始化操作:
若成员变量是内置类型:编译器不做处理,程序员可以在成员变量声明位置 可以给缺省值 ,编译器自动生成的构造函数就会用程序员给出的这个缺省值初始化成员变量。
若成员变量是自定义类型:编译器自动生成的构造函数就会调用他的默认构造函数
程序员需要自己分析类型成员和初始化需求,绝大多数场景都需要程序员自己实现构造函数!
什么是默认构造函数?
编译器自动生成的构造函数只是 默认构造函数之一。无参数的构造函数,全缺省的构造函数 也属于默认构造函数
总结:不需要传参 就可以调用的构造函数 ➡️默认构造函数,默认构造函数只能有一个
❓问题遗留:
class Time
{
public:
// 没有默认构造函数
Time(int hour)
{
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;
}
代码问题描述:
当前time类中 我们显示定义了构造函数 ,则编译器不会自动生成默认构造函数。Data类包含time类,time类没有默认构造函数,导致Data类编译器也无法为这个类自动生成默认构造函数。
报错如下:
此时,我们只能显示实现构造函数,详见 下期知识点初始化列表
三、析构函数
干嘛的 ?
清理资源,类似于 Desdory .
语法定义
1、析构函数名实在类名前面加上~
2、无参数无返回值类型
3、一个类只能有一个析构函数。程序员没定义,编译器自动生成析构函数。析构函数不能重载。
4、对象声明周期结束的时候,编译器自动调用
因为在函数栈帧里,所以先定义的后析构,后定义的先析构。
代码示例:我们创建不同生命周期不同作用域的对象,注意观察他们的析构顺序
#include<iostream>
using namespace std;
class Date
{
public:
Date(int year = 1)
{
_year = year;
}
~Date()
{
cout << "~Date()->"<<_year<< endl;
}
private:
// 基本类型(内置类型)
int _year;
int _month;
int _day;
};
void func()
{
Date d3(3);
static Date d4(4);
}
Date d5(5);
static Date d7(7);
Date d6(6);
static Date d8(8);
// 局部对象(后定义先析构) -》 局部的静态 -》全局对象(后定义先析构)
int main()
{
Date d1(1);
Date d2(2);
func();
return 0;
}
析构顺序
局部对象(后定义先析构) ➡️ 局部的静态 ➡️ 全局对象(无论静态or非静态 都是后定义先析构)
默认生成的析构函数跟构造函数类似,
如果要清理的资源是内置类型,则不做处理。若是自定义类型的成员,则编译器去调用它的析构函数
其他的默认成员函数我们会在下节介绍~