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

本文深入探讨C++中的构造、析构与赋值运算,解释默认成员函数的行为,如何拒绝不需要的编译器生成函数,多态基类中虚拟析构函数的重要性,以及预防异常从析构函数中逃逸的策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

构造/析构/赋值运算

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应该提供一个普通函数(而非在析构函数中)执行该操作。
自定义一个名为MyString的,我们可以按照标准步骤实现所需的功能: 1. 构造函数: ```cpp class MyString { private: std::string data; public: // 默认构造函数 MyString() : data{} {} // 拷贝构造函数 MyString(const MyString& other) : data(other.data) {} // 如果需要,可以提供带初始字符串的构造函数 explicit MyString(const std::string& str) : data(str) {} }; ``` 2. 函数(destructor): ```cpp ~MyString() {} // 默认函数,释放内部资源 ``` 3. 拷贝构造函数(copy constructor): ```cpp MyString& operator=(const MyString& other) { if (this != &other) { data = other.data; } return *this; } ``` 4. 赋值运算重载(assignment operator): ```cpp MyString& operator=(std::string&& str) { data = std::move(str); return *this; } ``` 5. [] 运算重载(数组访问): ```cpp char& operator[](size_t index) { if (index < data.size()) { return data[index]; } else { throw std::out_of_range("Array out of range"); } } const char& operator[](size_t index) const { if (index < data.size()) { return data[index]; } else { throw std::out_of_range("Array out of range"); } } ``` 6. + 运算重载(连接两个字符串): ```cpp MyString operator+(const MyString& other) const { MyString result(data); result.data += other.data; return result; } MyString operator+(const std::string& str) const { MyString result(data); result.data += str; return result; } ``` 7. += 运算重载(将一个字符串追加到当前字符串): ```cpp MyString& operator+=(const MyString& other) { data += other.data; return *this; } MyString& operator+=(const std::string& str) { data += str; return *this; } ``` 8. == 运算重载(比较两个字符串是否相等): ```cpp bool operator==(const MyString& other) const { return data == other.data; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值