当前位置: 首页 > backend >正文

六、初始化与清理(Initialization cleanup)

六、初始化与清理(Initialization & cleanup)

本章内容主要介绍C++中的 构造函数析构函数 的作用与用法,以及默认构造、聚合初始化等相关特性

  • 封装 和 *访问控制 *在提升库使用的便捷性方面迈出了重要的一步。
  • 在安全性方面,C++编译器比C能为我们做更多的事情。
  • 这些安全问题中有两个是 初始化清理

6.1 使用构造函数进行初始化(Initialization with the constructor)

特点(1)

  • 初始化过于重要,不能交由客户程序员处理。构造函数用于初始化对象。
  • 编译器会在创建对象时自动调用构造函数。
  • 构造函数的识别方式是它与类同名
  • 构造函数可以被重载
  • 构造函数没有返回值

有构造函数的简单class例子

class X
{int i;
public:X(){i = 0;}
};

现在,当一个对象被定义时,

void f(){X a;}

将为对象分配存储空间。构造函数会被自动调用,即X:x()

特点(2)

  • 和任何成员函数一样,构造函数的第一个(隐藏的)参数时this 指针——它是正在调用构造函数的对象(内存块)的地址。
  • 构造函数可以有参数。
  • 构造函数参数为你提供了一种方式,以确保对象的所有部分都被初始化为合适的值。

示例

#include <iostream>using namespace std;class Date
{int year,month,day;
public:Date(int y,int m,int d);void print(){cout << year << "." << month << "." << day << endl;}
};Date::Date(int y,int m,int d) //definiton
{year = y;month = m;day = d;
}void main()
{Date date(2005,7,5);date.print();
}

输出

2005,7,5

使用析构函数进行清理(Cleanup with the destructor)

概述

  • 在C++中,清理适合初始化一样重要的。
  • 析构函数(Destructor)可以用于对象销毁的清理操作。
  • 特点
    • 名字为~类名
    • 无参数,不可重载
    • 无返回值
    • 编译器在对象销毁时自动调用

构造函数和析构函数

编号构造函数(Constructor)析构函数(Destrucetor)
1构造函数用于初始化对象并构造指定类型的值。析构函数用于清理并释放资源。
2构造函数通过与类同名来识别。析构函数通过与类同名并带有符号~ 来识别。
3构造函数可以有形式参数,并且可以被重载析构函数没有形式参数不能被重载
4构造函数没有返回值。析构函数没有返回值。
5在对象被创建时会自动调用构造函数。在对象被销毁时会自动调用析构函数。

示例

#include <iostream>using namespace std;class Date
{int year,month,day;
public:Date(int y,int m,int d)//constructor{year = y;month = m;day = d;cout << "Constructor called." << endl;}~Date(){cout << "Destructor called." << endl;}//Destructorvoid Print(){cout << year << "." << month << "." << day << "." << endl;}
};void main()
{Date today(2025,4,23),tomorrow(2025,4,24);cout << "Today is ";today.Print();cout << "Tomorrow is ";tomorrow.Print();
}

输出:

Constructor called.    //Today
Constructor called.    //Tomorrow
Today is 2025.4.23.
Tomorrow is 2025.4.24.
Destructor called.		//Tomorrow
Destructor called.		//Today

析构顺序是 先建后析 ,和栈一样

//C06:Constructor1.cpp
//Constructor & destructor
#include <iostream>
using namespace std;
class Tree
{int height;
public:Tree(int initialHeight);//Constructor~Tree();//Destructorvoid grow(int years);void printsize();
};Tree::Tree(int initialHeight)
{height = initialHeight;
}
Tree::~Tree()
{cout << "inside Tree destructor" << endl;printsize();
}
void Tree::grow(int years)
{height+=years;
}
void Tree::printsize()
{cout << "Tree height is " << height << endl;
}void main()
{cout << "before opening brace" << endl;{Tree t(12);cout << "after Tree creation" << endl;t.printsize();t.grow(4);cout << "before closing brace" << endl;}cout << "after closing brace" << endl;
}

输出:

before opening brace
after Tree creation
Tree height is 12
before clong brace
inside Tree destructor
Tree height is 16
after closing brace

6.3 消除定义块(Elimination of the definition block)

  • C++支持在作用域的任意位置定义变量。
  • 最佳实践
    • 尽可能靠近使用初定义变量
    • 定义时初始化
  • 这样做有助于提升安全性与代码可读性

6.4 Stash类(含构造函数和析构函数)

Stash2.h

//C06:Stash2.h
#ifndef STASH2_H
#define STASH2_H
class Stash
(int size; // Size of each spaceint quantity; //Number of storage spacesint next;// Next empty spaceunsigned char* storage;void inflate(int increase);
public:Stash(int size);~Stash();int add(void* element);void* fetch(int index);int count();
);
//endif

Stash2.cpp

//C06:Stash2.cpp
#include "Stash2.h"
#include <iostream>
#include <assert>
using namespace std;
const int increment = 100;
Stash::Stash(int sz){size = sz;quantity = 0;storage = 0;next = 0;}
int Stash::add(void* element){…………}
void* Stash::fetch(int index){…………}
int Stash::count(){…………}
void Stash::inflate(int increment){…………}
Stash::~Stash(){if (storage != 0){cout << "freeing storage" << endl;delete []storage;}
}

6.5 Stack类(含构造函数和析构函数)

Stack3.h

//C06:Stack3.h
#ifndef STACK3_H
#define STACK3_H
class Stack{struct Link{void* data;Link* data;Link* next;Link(void* dat,Link* nxt);~Link();}* head;
public:Stack();~Stack();void push(void* dat);void* peek();void* pop();
};
#endif

Stack3.cpp

//C06:Stack3.cpp
#include "Stack3.h"
#include <cassert>
using namespace std;Stack::Link::Link(void* dat,Link* nxt){data = dat;next = nxt;
}
Stack::Link::~Link(){}
Stack::Stack(){head = 0;}
void Stack::push(void* dat){head = new Link(dat,head);
}
void* Stack::peep(){assert(head!=0 && "Stack empty");return head->data;
}
void* Stack::pop(){if (head == 0) return 0;void* result = head->data;Link* oldHead = head;head = head->next;delete oldHead;return result;
}Stack::~Stack(){assert(head==0 && "Stack not empty");}

6.6 聚合初始化(Aggregate Initialization)

概述

聚合初始化 是C++中一种通过大括号 {} 一次性为所有成员赋值 的方式 。它专门用于“简单的结构体或类”,也就是所谓的“聚合类型”,但也不限于聚合类型。

聚合类型的特点

  • 没有用户自定义的构造函数
  • 所有成员都是public
  • 没有基类
  • 没有虚函数

数组初始化

int a[5] = {1,2,3,4,5};
int b[6] = {2};
int c[] = {1,2,3,4};
  • 一个数组的size = sizeof(c)/sizeof(c[0])

对象数组初始化

Date y[2] = {Date(2001,2,3),Date(2003,4,5)};Date y[3];
y[0] = Date(2001,2,3);
y[1] = Date(2003,4,5);
y[2] = Date(2003,4,5);

示例

#include <iostream>
using namespace std;class Date
{int year,month,day;
public:Date(){year = month = day = 0;cout << "Default constructor called." << endl;}Date(int y,int m,int d){year = y;month = m;day = d;cout << "Constructor called." << day << endl;}~Date(){cout << "Destructor called." << day << endl;}void Print(){cout << year << "." << month << "." << day << endl;}
};void main()
{Date date[3] = {Date(2003,9,20),Date(2003,9,21)};for (int i = 0;i < 3 ;i++){date[i].Print();}
}

输出:

Construcor called.20
Construcor called.21
Default constructor called.
2003.9.20
2003.9.21
0.0.0
Destructor called.0
Destructor called.21
Destructor called.20

6.7 默认构造函数

特点

  • 可以被无参调用。
  • 若用户未定义构造函数,编译器会默认生成一个。
  • 建议 显示定义构造函数,以增强控制力。

6.8 总结

  • 构造函数(初始化对象)
  • 析构函数(销毁时清理资源)
  • 默认构造函数
  • 聚合初始化
  • 构造与赋值的区别
http://www.xdnf.cn/news/1809.html

相关文章:

  • Spring Boot 整合 Lock4j + Redisson 实现分布式锁实战
  • YOLOv11架构革新——基于RFEM模块的小目标感受野增强与特征优化
  • 如何管理“完美主义”导致的进度拖延
  • 高德地图API + three.js + Vue3基础使用与使用 + 标记不显示避坑
  • IMX6ULL 最新方案移植教程中间间系列5——向开发板迁移SSH和FTP
  • LeetCode hot 100—最长有效括号
  • 【FAQ】安装Agent的主机,为何不能更改显示分辨率
  • CVE-2025-32102 | Ubuntu 下复现 CrushFTP telnetSocket接口SSRF
  • dataType 和 content-type 参数的作用
  • 补4月22日23日
  • Sentieon软件发布V202503版本
  • 首版次软件产品有哪些阶段?专业软件测试服务公司分享
  • 使用String path = FileUtilTest.class.getResource(“/1.txt“).getPath(); 报找不到路径
  • Spring Boot 中配置线程池时优化 `ThreadPoolTaskExecutor` 的配置总结
  • DDL小练习
  • Java小公司实习面经
  • python字符串(3):字符集/编码(查看修改字符集,乱码);码点和字符的转换(chr和ord),字符串的编码解码函数(encode,decode)
  • Dockerfile指令
  • JavaScript 实现继承及 Class 本质详解
  • 【Python Web开发】02-Socket网络编程02
  • Java 高频面试题解析
  • Langchain提取结构化数据
  • 第九节:性能优化高频题-首屏加载优化策略
  • JS Array 方法 | 区分 slice 和 splice
  • `rfind()` 从字符串的右侧开始查找指定子字符串首次出现的位置
  • SiamFC算法深度解析
  • 深入浅出:Pinctrl与GPIO子系统详解
  • SpringCloud微服务架构设计与实践 - 面试实战
  • C语言别踩白块附源码
  • Trae+DeepSeek学习Python开发MVC框架程序笔记(四):使用sqlite存储查询并验证用户名和密码