未来做那个网站致富,天津重型网站建设方案公司,磁力搜索网站怎么做的,网站seo优化怎么做#x1f525;个人主页#xff1a;Forcible Bug Maker
#x1f525;专栏#xff1a;C
目录
前言
类的6个默认成员函数
构造函数
概念
构造函数的特性及用法
析构函数
概念
析构函数的特性及用法
结语 前言 本篇主要内容#xff1a;类的6个默认成员函数中的构造函…
个人主页Forcible Bug Maker
专栏C
目录
前言
类的6个默认成员函数
构造函数
概念
构造函数的特性及用法
析构函数
概念
析构函数的特性及用法
结语 前言 本篇主要内容类的6个默认成员函数中的构造函数和析构函数 进入到类和对象内容的第二节上篇博客中介绍了类和对象的一些基本特性接下来就要讲到类的六个默认成员函数。C类的六个默认成员函数包括构造函数、析构函数、拷贝构造函数、赋值运算符重载、取地址重载和const取地址重载。这些函数在特定情况下会被编译器自动生成但你也可以根据需要自定义它们。
类的6个默认成员函数
在一个类中如果你什么都不往里写那么就可以称这个类为空类。实际上在你什么都不往空类里写时编译器会自动生成以下6个默认成员函数。 默认成员函数用户没有显式实现编译器会生成的成员函数称为默认成员函数。 // 这是一个空类
class Date {}; 构造函数、析构函数、拷贝构造函数、赋值运算符重载、取地址重载和const取地址重载。 构造函数
概念
接下来举个例子引入构造函数。如果你写了一个存储日期的类Date在使用Date定义的对象之前都需要像C语言一样调用一遍初始化。
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()
{Date d1;d1.Init(2022, 7, 5);d1.Print();Date d2;d2.Init(2022, 7, 6);d2.Print();return 0;
}
你看使用对象d1和d2之前都需要调用一遍Init函数来给对象设置日期但如果每次创建对象时都调用该方法未免有些麻烦是否存在某种方式在创建对象时就将信息设置进去呢答案是有的解决方式就是今天的构造函数。 构造函数是一个特殊的成员函数名字与类名相同创建类类型对象时由编译器自动调用以保证每个数据成员都有 一个合适的初始值并且在对象整个生命周期内只调用一次。 构造函数的特性及用法 构造函数是特殊的成员函数需要注意的是构造函数虽然名称叫构造但是构造函数的主要任务并不是开空间创建对象而是初始化对象。 1. 函数名和类名相同。
2. 无返回值不是void而是根本就不用写其返回值。
3. 对象实例化时编译器自动调用对应的构造函数。
4. 构造函数可以重载
class Date
{
public:// 1.无参构造函数Date(){}// 2.带参构造函数Date(int year, int month, int day){_year year;_month month;_day day;}
private:int _year;int _month;int _day;
};
void TestDate()
{Date d1; // 调用无参构造函数Date d2(2015, 1, 1); // 调用带参的构造函数
} 注如果通过无参构造函数创建对象时对象后面不用跟括号否则就成了函数声明。 Date d3();
如果你写下这样一行代码来创建对象就大错特错了。这句话会被编译器解读成一种函数声明其细节是声明了d3函数该函数无参返回一个日期类型的对象无法达到创建对象的目的。
5. 如果类中没有显式定义构造函数则C编译器会自动生成一个无参的默认构造函数一旦用户显式定义编译器将不再生成 其中定义了传参的构造函数无参的默认构造将被覆盖也就是说此时定义变量不传参会编译失败报错error C2512: “Date”: 没有合适的默认构造函数可用。 6. C把类型分成内置类型(基本类型)和自定义类型。对于内置类型C默认生成的构造函数对内置类型不做处理所以未定义自定义类型中的数据为随机值对自定义类型的成员会去调用它的默认构造不用传参数的构造。内置类型就是语言提供的数据类型如int/char...自定义类型就是我们使用class/struct/union等自己定义的类型。 就比如上面的代码Date类中默认生成的构造函数调用了自定义类型 _t 的无参构造函数。 注C11 中针对内置类型成员不初始化的缺陷又打了补丁即内置类型成员变量在类中声明时可以给默认值。 上面代码给了内置类型缺省值在生成d对象之后内置类型也就成功被缺省值赋值了。
7. 无参的构造函数和全缺省的构造函数都称为默认构造函数并且默认构造函数只能有一个。 注默认构造不传参就可以调用的函数。故无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数都可以认为是默认构造函数。 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;
};
// 以下测试函数能通过编译吗
void Test()
{Date d1;
}
根据第七点我们知道Test函数是不能通过编译的在类中定义了两个默认构造不传参就可以调用的构造函数编译器无法确认应该调用哪一个模棱两可的代码是编程的大忌。 析构函数
概念
通过了前面构造函数的学习我们认识了可以在创建对象时帮助初始化的函数那相应的是否就应该有对对象进行自动销毁和清理的函数呢答案是有的。 析构函数与构造函数功能相反析构函数不是完成对对象本身的销毁局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数完成对象中资源的清理工作。 析构函数的特性及用法 析构函数是特殊的成员函数它在对象的生命周期结束时自动被调用用于执行清理工作如释放动态分配的内存、关闭打开的文件、断开网络连接等。析构函数与类名同名但前面加上一个波浪号~并且没有返回类型和参数。 1. 析构函数名是在类名前加上字符 ~ 。
2. 无参数无返回值类型。
3. 一个类只能有一个析构函数。若未显示定义系统会自动生成默认的析构函数。注意析构函数不能重载。
4. 对象生命周期结束时C编译系统自动调用析构函数。
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;}void Push(DataType data){// CheckCapacity();_array[_size] data;_size;}// 其他方法...~Stack(){if (_array){free(_array);_array NULL;_capacity 0;_size 0;}}
private:DataType* _array;int _capacity;int _size;
};
void TestStack()
{Stack s;s.Push(1);s.Push(2);
}上份代码可以把重点放在构造函数和析构函数上。在构造函数Stack中使用malloc在堆上开辟了一块空间使用内置类型 _capacity 和 _size 来维护整个栈最后定义了析构函数~stack在此函数中我们在函数内部实现了堆中占用内存的释放。
什么你告诉我你不知道什么是栈推荐你看看这篇博客初阶数据结构之---栈和队列C语言 指针类型属于内置类型 如果不自己实现析构函数编译器会将_array当作内置类型在自动生成的析构函数中不会释放堆中占用的空间导致内存泄露。
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;
} 你会发现在main方法中根本就没有直接创建Time类的对象但是最后还是调用了Time类的析构函数。是因为在main方法中创建了Date对象d而d中包含4个成员变量其中_year_month_day三个是内置类型成员销毁时不需要资源清理最后直接将其内存回收即可而_t是Time类对象所以在d销毁时要将其内部包含Time类的_t对象销毁所以要调用Time类的析构函数。但是main函数中不能直接调用Time类的析构函数实际释放的是Date类对象所以编译器会调用Date类的析构函数而Date没有显示提供则编译器会给Date类生成一个默认的析构函数目的是在其内部调用Time类的析构函数即当Date对象销毁时能保证内部每个定义的对象都可以正确销毁。 注创建哪个类的对象则调用该类的析构函数销毁哪个类的对象则调用该类的析构函数 6. 类中没有申请资源时析构函数可以不写直接使用编译器生成的默认析构函数比如Date类有资源申请时一定要写否则会造成内存泄露如Stack类。
结语
本篇博客将重点放在了类和对象六个默认成员函数的前两个构造函数和析构函数上。这两个默认成员函数在对象的生命周期中起着至关重要的作用。构造函数确保对象在创建时能够正确初始化而析构函数则确保对象在销毁时能够正确清理资源从而保持程序的稳定性和安全性。在下一篇博客中我会介绍拷贝构造函数、赋值运算符重载、取地址重载和const取地址重载另外四大默认成员函数的内容敬请期待。
本篇博客到此结束感谢大家的支持♥