C++的构造、析构函数
来源:互联网 发布:加载寄售物品数据库 编辑:程序博客网 时间:2024/06/11 06:39
构造、析构函数的由来:
由于C++类是许多成员函数和成员变量的集合,在实例化一个类时肯定需要将其内部变量初始化,而这个工作如果由程序员在创建对象后显示调用初始化函数完成,恐怕难免会有疏漏,所以C++之父发挥程序员“”懒惰“的特性,规定了两个函数分别是构造和析构函数,来完成初始化和清理工作,而这两个函数很重要的一点是,他们是在对象创建和消亡时自动执行的。
特别的是,如果程序员没有定义构造和析构函数,编译器会自动生成,但这只是需有其表而已,有时还有带来错误,例如自动生成的拷贝构造函数,是按位拷贝的,当有指针变量时,就会带来问题,所以建议还是主动定义构成和析构函数,而像拷贝构造函数和赋值函数,不需要使用最好主动禁止它们,方法是在private权限下只声明而不定义它们。
class String{public: String(const char *str = NULL); String(const String &other); ~String(); String& operator=(const String &other);private: char *m_data;};String::String(const char *str){ if (NULL == str) { m_data = new char[1]; *m_data = '\0'; } else { m_data = new char[strlen(str)+1]; strcpy(m_data, str); }}String::String(const String &other){ m_data = new char[strlen(other.m_data)+1]; strcpy(m_data, other.m_data);}String::~String(){ delete[] m_data;/* delete m_data;*/}String& String::operator =(const String &other){ String tmp(other); char *orig = m_data; m_data = tmp.m_data; tmp.m_data = orig; return *this;/* if (this == other) return *this; delete[] m_data; m_data = new char[strlen(other.m_data)+1]; strcpy(m_data, other.m_data); return *this;*/}
以上代码是String类的简单实现,从中我们可以总结几点:
1、构造函数和析构函数的函数名必须与类名相同,保证编译器能明确识别。而且都不能有返回值,这也许是由于它们在对象创建和消亡时自动执行,没必要返回任何值,又或许是因为没有返回值显得比较另类,以突出它们的特殊性吧。注意赋值函数不是构造函数,从返回值这一点就能看出。
2、构造函数可以有多个,包含一个拷贝构造函数,以提供灵活的对象初始化方式,而这也是重载存在的必要性。但析构函数不能有多个,不然编译器无法确定使用哪个。
3、拷贝构造函数的参数需要为引用类型,如果是传值,那么在实参拷贝到形参时又会调用拷贝构造函数,也就是发生无限递归,这会导致栈溢出,所以C++编译器会直接禁止参数为传值形式的拷贝构造函数声明。
4、赋值函数(针对上述代码):
1)由于原来对象中的申请的空间不一定能满足拷贝需求,所以需要重新申请,但不能简单的释放资源后再申请资源然后拷贝内容。这样存在两个问题,自我赋值和异常安全性。当赋值的两个对象为同一个时,释放了源对象资源也就是释放了被拷贝对象的资源,之后再去拷贝内容时,拷贝的是一段已释放的空间;还有一个问题是如果new执行失败,而对象里的资源已经被释放,那么该对象中相当于保存了一个野指针。
2)处理这两个问题的关键在于不能提前释放对象里的资源,可以向对象里的指针指向新的地址,然后将指向地址里的空间释放,而上述代码里设计更为巧妙,先创建一个局部对象,将内容拷贝到这个局部对象,再互换原对象和局部对象的空间资源,当函数退出后,局部对象会调用析构函数释放空间,而这段空间恰好是原对象的最初那段空间。这样处理后同样也解决了自我赋值的问题。
3)关于new和delete操作符,当new失败时,它并不会返回NULL(可能老版本为了兼容C是这样处理的),而是会抛出异常,而delete如果new时用的是[],delete也需要用[].
参考文献:《高质量C++编程指南》
6、由于构造、析构函数不能够继承,所以派生类的构造函数应该在初始化列表中调用基类的构造函数;
7、基类和派生类的构造函数应该为虚(virtual);
8、构造和析构的次序:
构造函数遵循从内向外构造的次序,即先构造基类,再派生类,然后一层层向外的次序。
析构函数正好想法,即先析构最外层,逐渐向内层析构。
- c++/string的构造析构函数
- C/C++——构造函数、复制构造函数和析构函数的执行时刻
- 关于c++默认的构造函数、析构函数、拷贝构造函数、move函数
- C语言的构造函数与析构函数
- Object-C 的构造函数析构函数
- [c++]派生类的构造函数和析构函数
- C++:类的构造函数和析构函数
- 【C++】构造函数&析构函数的解析(应用)
- c++---派生类的构造函数和析构函数
- 构造函数和析构函数【c++】
- c++-构造函数与析构函数
- C++-构造函数,析构函数
- [c++]构造函数和析构函数
- C++--构造函数与析构函数
- 【C#】构造函数和析构函数
- 【C++】构造函数和析构函数
- 【C++】构造函数和析构函数
- C++(构造函数&&析构函数)
- linux adb无法连接的问题
- 阿里2015年4月实习生招聘研发岗笔试题——RPC题解
- 基于Lockset的数据竞争检测方法汇总(二)
- 记事本在读取一个文本时如何判断是该用啥字符集来读取解析文本字符
- 多选AlertDialog至多选择3项
- C++的构造、析构函数
- 网页刷新或者重新加载后滚动条的位置不变
- 浅谈10个重要的Linux ps命令
- 黑马程序员——Java基础:面向对象一些概念的区分(二)
- 字符串读入和输出问题
- Ubuntu14.04安装搜狗输入法
- UML图
- i=i++分析
- 分享一下官网USB读卡器移植 --> 附上原子战舰的测试工程(TF卡SDIO模式 + SPI-flash)