六、初始化与清理(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 总结
- 构造函数(初始化对象)
- 析构函数(销毁时清理资源)
- 默认构造函数
- 聚合初始化
- 构造与赋值的区别