【C++基础六】类和对象—中(构造和析构函数)
【C++基础六】类和对象—中
- 1.什么是构造函数
- 2.默认构造函数
- 3.深入理解构造函数
- 4.什么是析构函数
- 5.深入理解析构函数
- 6.C++11新功能
我们平时写数据结构时,经常忘记写或者调用初始化函数,使得栈中的变量是随机值,易出错
有时忘记调用销毁函数,导致内存泄漏
因此诞生了构造和析构函数
1.什么是构造函数
构造函数,,是用于初始化的函数
- 函数名与类名相同
- 无返回值
- 对象实例化时自动调用对应的构造函数
- 构造函数可以重载
注意:
- 构造函数是特殊的成员函数,不能将它与普通函数对比
- 构造函数的任务是初始化对象,而不是开辟空间创造对象
例:
class Date
{
public:
Date(int year, int month, int day)//含参的构造函数
{
_year = year;
_month = month;
_day = day;
}
Date()//无参的构造函数
{
_year = 2025;
_month = 3;
_day = 12;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d2(2023, 3, 12);//调用含参的构造
Date d1;//调用无参构造函数
}
构造函数是实例化对象时就调用
2.默认构造函数
如果没有显示的写构造函数,系统就会自动生成一个默认构造函数
对象d1没有传参数,会生成对应的无参默认构造,无报错
例:
有默认构造
没有显示的写构造函数,系统默认构造无参的
class Date
{
public:
// 如果用户显式定义了构造函数,编译器将不再生成默认构造函数
/*Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}*/
private:
int _year;
int _month;
int _day;
};
int main()
{
// 将Date类中构造函数屏蔽后,代码可以通过编译,因为编译器生成了一个无参的默认构造函数
Date d1;
return 0;
}
无默认构造
没有显示的写了构造函数Date,系统不会生成默认构造函数
但对象d1初始化时,只有含参的构造函数,没有无参的构造函数,又没有系统的默认构造,所以会报错
class Date
{
public:
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
//将Date类中构造函数放开,代码编译失败
//因为一旦显式定义任何构造函数,编译器将不再生成默认构造函数
Date d1;//无参构造函数,放开后报错:error C2512: “Date”: 没有合适的默认构造函数可用
return 0;
}
3.深入理解构造函数
既然编译器会自己生成构造函数,那我是不是写不写构造函数都可以了?
答案是否定的
C++中有两种类型:
- 内置类型:是C++语言提供的类型,比如: int/char类型
- 自定义类型:是用户使用class类,定义出来的类型,如:Date类
class Date
{
private:
// 基本类型(内置类型)
int _year;
int _month;
int _day;
};
int main()
{
Date d;
return 0;
}
Date类没有显示写构造函数,所以编译器会自动生成一个无参的默认构造函数,此构造函数不会处理内置类型,所以成员变量:中的year,month,day都是随机值
class Time
{
public:
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;
}
d没有显示的写构造函数,所以系统自动生成了一个默认构造函数,当处理到自定义类型时,这个默认构造函数会去调用Time类中的构造函数,将成员变量_t初始化
默认构造函数的特性:
- 自动生成的默认构造函数不会处理内置类型,内置类型的值都会是随机值
- 但自动生成的默认构造函数会去调用自定义类型的构造函数去处理自定义类型
默认构造函数可以是下面的类别:
- 编译器自动生成的默认构造
- 显示写的无参的构造函数
- 显示写的全缺省的构造函数
class Date
{
public:
Date()//无参构造函数
{
_year = 1900;
_month = 1;
_day = 1;
}
Date(int year = 1900, int month = 1, int day = 1)//全缺省构造函数
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
4.什么是析构函数
析构函数和构造函数类似
且编译器自动生成的默认析构函数,只处理自定义类型,而不处理内置类型
函数名前加上~
就是析构函数
内置类型虽然不会被析构函数销毁,但内置类型会在对象生命周期结束时,把它在栈区的空间还给操作系统,所以析构函数不处理在栈区的变量也没有问题
但有些变量的指针指向堆区,有动态开辟出来的空间,这份空间不会主动还给操作系统,需要我们手动写析构函数来释放
例:
typedef int DataType;
class Stack
{
public:
Stack(size_t capacity = 3)//构造函数
{
_array = (DataType*)malloc(sizeof(DataType) * capacity);
if(NULL == _array)
{
perror("malloc申请空间失败!!!");
return;
}
_capacity = capacity;
_size = 0;
}
~Stack()//析构函数
{
if (_array)
{
free(_array);
_array = NULL;
_capacity = 0;
_size = 0;
}
}
private:
DataType* _array;
int _capacity;
int _size;
};
void TestStack()
{
Stack s;
}
这段代码中,有在堆区申请的空间,所以不能使用编译器默认生成的析构,而是要用自己写的析构函数去free掉这块堆区的空间
5.深入理解析构函数
和构造函数一样,默认析构函数会去调用自定义类型的析构函数
class Time
{
public:
~Time()
{
cout << "~Time()" << endl;
}
private:
int _hour;
int _minute;
int _second;
};
class Date
{
private:
//内置类型
int _year = 1970;
int _month = 1;
int _day = 1;
//自定义类型
Time _t;
};
int main()
{
Date d;
return 0;
}
当d的生命周期结束时,系统会自动调用析构函数,而Date类没有显示写析构函数,就会 使用编译器自动生成的默认析构函数
销毁到自定义类型时,当前默认析构函数就会调用Time类中的析构函数
6.C++11新功能
C++11 中针对内置类型成员不初始化的缺陷又打了补丁
即:内置类型成员变量在类中声明时可以给默认值
class Time
{
public:
Time()
{
cout << "Time()" << endl;
_hour = 0;
_minute = 0;
_second = 0;
}
private:
int _hour = 1;//声明的时候给缺省值
int _minute = 1;
int _second = 1;
};
如果用户没有显示传参,那么hour,minute,second的值都会初始化为1