构造/析构/赋值运算(一)

构造/析构/赋值运算

Constructors,Destructors,and Assignment Operators

5.了解C++默认成员函数

Know what functions C++ silently writes and calls.

  1. C++默认成员函数有哪些?
    在这里插入图片描述
  2. 默认析构函数是个non-virtual,除非这个class的bass class自身声明有virtual析构函数。
  3. 如果默认拷贝构造需要拷贝的成员是内置类型,那么会以“拷贝源对象的每一个bits”来完成初始化。如果拷贝的对象不是内置类型(如string类型),那么拷贝会调用string的拷贝构造来完成。
  4. 默认copy assignment会在不违反C++语言特性的基础上为程序员完成对象拷贝。
class Object{
public:
	Object(string& s,const T& value);
	string& s;
	const T object_value; 
};
......
std::string str1("Hello");
srd::string str2("Gun");
Object<std::string,int> o1(str1,666);
Object<std::string,int> o2(str2,438);
o1=o2;//调用默认的赋值运算符是不会得逞的。

o1的成员string&是reference,不能改指向不同对象,o1的成员const T具有const属性,也不能被改变。

除构造函数外,其余成员函数调用过程都需要使用隐含的this指针去完成调用。

关于C++中默认的成员函数相关知识,推荐阅读:http://c.zhizuobiao.com/c-19012100036/

6.如果不想使用编译器默认生成的函数,就该明确拒绝

Explicitly disallow the use of compiler-generated functions you do not want.

  1. 将默认函数声明私有化(private类型函数),并且不定义(防止friend函数调用,直接不实现)。
#include<iostream>
class No_copy {
private:
	No_copy(No_copy&);
	No_copy& operator=(const No_copy&);
};

拷贝构造和重载赋值操作符对象自身可见,友元函数可见,但是我的函数并未实现,也不能调用。
2.

class No_copy{
protected:
	No_copy (){}
	~No_copy (){}
private:
	No_copy (const No_copy &);
	No_copy& operator=(const No_copy &);
};
 
class No_copy_son:private No_copy 
{
	.......
};

派生类无法调用基类的私有成员函数,无法实现拷贝或者赋值。
3. C++11太人性化,没天理。

#include<iostream>
class No_copy {
private:
	No_copy(No_copy&)=delete;
	No_copy operator=(const No_copy&)=delete;
};

7.为多态基类声明virtual析构函数

Declare destructors virtual in polymorphic base classes.

  1. 析构函数最好是虚函数。 在多态场景下,如果析构函数不是virtual的,通过base class指针删除derived class,会出现结果未定义,通常发生的是derived class未被销毁。而销毁掉了base class对象,形成资源泄漏等问题。
#include<iostream>
class Father {
public:
	Father()
	{	
		father_ptr = new char[10];
		std::cout << "Father()" << std::endl;
	}
	~Father()
	{	
		delete[] father_ptr;
		std::cout << "~Father()" << std::endl;
	}
private:
	char* father_ptr;
};
class Son :public Father
{
public:
	Son()
	{
		son_ptr = new char[5];
		std::cout << "Son()" << std::endl;
	}
	~Son()
	{
		delete[] son_ptr;
		std::cout << "~Son()" << std::endl;
	}
private:
	char* son_ptr;
};

int main()
{
	Father* pp = new Son;
	delete pp;
}
Father()
Son()
~Father()

F:\代码\Project1\Debug\Project1.exe (进程 10520)已退出,返回代码为: 0。
若要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口...

析构函数没有定义成虚函数,造成了内存泄漏。

  1. 只有当class内含有至少一个virtual函数,才为它声明virtual析构函数。classes的设计目的不是作为base classes使用,或不是为了具备多态性,就不该声明virtual析构函数(增加vptr会增加对象大小)。
  2. STL的string、vector、list等容器均是non virtual析构函数,不要企图让这些容器作为base class。
  3. 有时候令class带有纯虚析构函数,可能颇为便利。最好对纯虚析构函数进行定义,因为derived class析构函数会调用base的析构函数。

8.别让异常逃离析构函数

Prevent exception from destructors.

  1. 如果析构函数抛出异常会过早结束或者出现不明确行为。C++很不喜欢析构函数抛出异常。
  2. 如果析构函数必须执行一个动作,而该动作可能会在失败时抛出异常。那么最好赋予客户一个处理异常的机会。而如果在客户处理“因该操作发生的异常”之后,仍然无法避免异常,那么最终只有“强迫结束程序”或者“吞下异常”。
class DBConn{
public:
	void close()
	{
		db.close();
		closed=true;
	}
	~DBConn()
	{
		if(!closed){
			try{
				db.close();
			}
			catch(...){
				//abort()强迫结束程序,可抢先制止不明确行为
				//或者记录异常行为吞下异常
			}			
		}
	}
private:
	DBConnection db;
	bool closed;
};
  • 如果客户需要对某个操作函数运行期间抛出的异常做出反应,那么class应该提供一个普通函数(而非在析构函数中)执行该操作。
发布了139 篇原创文章 · 获赞 55 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/Vickers_xiaowei/article/details/102363912