重载赋值运算符

// overrideassignoperator.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

template <class T>
class Matrix
{
public:
	// brief : 构造函数
	// param : nil
	Matrix(int row, int col)
	{
		m_m = new T[row * col];
		m_row = row;
		m_col = col;
	}
	
	// brief : 拷贝构造函数
	// param : nil
	Matrix(const Matrix &m)
	{
		m_m = new T[m.m_row * m.m_col];
		m_row = m.m_row;
		m_col = m.m_col;
		memcpy_s(m_m, sizeof(T) * m.m_row * m.m_col, m.m_m, sizeof(T) * m.m_row * m.m_col);
	}

	// brief : 析构函数
	// param : nil
	~Matrix()
	{
		if(m_m)
			delete m_m;
		m_m = NULL;
		m_row = 0;
		m_col = 0;
	}
	
	// brief : 第一个重载赋值运算符
	// param : m 数据指针
	//         return 当前实例的引用
	Matrix &operator= (const T *m)
	{
		memcpy_s(m_m, sizeof(T) * m_row * m_col, m, sizeof(T) * m_row * m_col);
		return *this;
	}

	// brief : 第二个重载赋值运算符
	// param : m 矩阵
	//         return 当前实例的引用
	Matrix &operator= (const Matrix<T> &m)
	{
		if(this == &m)
			return *this;// 这个判定是为了支持拷贝本身
		if(m_m)
			delete m_m;
		m_m = new T[m.m_row * m.m_col];
		m_row = m.m_row;
		m_col = m.m_col;
		memcpy_s(m_m, sizeof(T) * m.m_row * m.m_col, m.m_m, sizeof(T) * m.m_row * m.m_col);
		return *this;
	}

public:
	T *m_m;
	int m_row;
	int m_col;
};

int _tmain(int argc, _TCHAR* argv[])
{
	// 定义2x2矩阵
	Matrix<float> M(2, 2);

	// 调用第一个重载赋值运算符,使用数组赋值
	float _M[4] = {0.1f, 0.2f, 0.3f, 0.4f};
	M = _M;

	// 调用第二个重载赋值运算符,拷贝矩阵本身
	M = M;

	// 调用拷贝构造函数,使用矩阵初始化
	Matrix<float> S = M;

	// 首先调用第二个重载赋值运算符,使用矩阵赋值,
	// 然后调用拷贝构造函数,使用矩阵初始化,进行嵌套拷贝
	Matrix<float> T = S = M;
	return 0;
}

### 重载赋值运算符 `=` 的方法与实现 在 C++ 中,赋值运算符 `=` 的重载是实现自定义类行为的重要组成部分。默认情况下,编译器会为每个类自动生成一个赋值运算符,该运算符对类的所有数据成员执行逐成员的浅拷贝。然而,在涉及资源管理(如动态内存、文件句柄等)时,必须显式重载赋值运算符以避免资源泄漏或重复释放等问题。 #### 基本格式 赋值运算符重载函数的格式包括以下几个关键部分: - **返回值类型**:通常是类类型的引用(`类名&`),以支持链式赋值操作。 - **函数名**:使用 `operator=` 表示重载赋值运算符。 - **参数列表**:通常是一个常量引用类型的参数(`const 类名&`),以避免不必要的拷贝。 - **返回值**:应返回当前对象的引用(`*this`)。 示例代码如下: ```cpp class BGPart { public: int s; BGPart& operator=(const BGPart& p) { if (this != &p) { s = p.s * 10; } return *this; } }; ``` 此实现中,首先检查是否是自赋值(即对象赋值给自己),以避免不必要的操作;然后执行实际的赋值逻辑;最后返回当前对象的引用以支持链式赋值[^4]。 #### 支持多参数赋值 虽然赋值运算符通常只接受一个参数(即另一个对象的引用),但也可以接受额外的参数,前提是这些参数必须具有默认值。例如: ```cpp Array& operator=(const Array& arr, int a = 100); ``` 这种方式允许在赋值过程中传递额外的控制参数,但并不常见,主要用于特定的扩展需求[^1]。 #### 避免自赋值问题 在实现赋值运算符时,必须处理自赋值的情况。如果不进行判断,直接对对象自身的资源进行释放和重新分配,可能导致未定义行为。因此,应在函数开头加入类似 `if (this != &p)` 的判断[^4]。 #### 返回类型的重要性 返回类型为类的引用(`类名&`)是为了支持连续赋值,例如 `a = b = c;`。若返回类型为 `void` 或者返回一个临时对象,则无法支持这种链式操作。因此,返回 `*this` 是标准做法[^2]。 #### 默认赋值运算符的行为 如果程序没有显式提供赋值运算符重载函数,编译器会自动生成一个默认版本。该默认实现会对每个成员变量进行逐个赋值。在大多数情况下,这种默认行为是合适的,除非类中包含指针或需要深拷贝的资源[^3]。 --- ### 示例代码 以下是一个完整的示例,展示了如何实现一个带有资源管理的类的赋值运算符: ```cpp #include <iostream> using namespace std; class MyString { private: char* data; public: MyString(const char* str = "") { data = new char[strlen(str) + 1]; strcpy(data, str); } ~MyString() { delete[] data; } MyString(const MyString& other) { data = new char[strlen(other.data) + 1]; strcpy(data, other.data); } MyString& operator=(const MyString& other) { if (this != &other) { char* newData = new char[strlen(other.data) + 1]; strcpy(newData, other.data); delete[] data; data = newData; } return *this; } void print() const { cout << data << endl; } }; int main() { MyString s1("Hello"); MyString s2("World"); s2 = s1; s2.print(); // 输出: Hello } ``` 此示例中,`MyString` 类管理一个动态分配的字符数组。赋值运算符重载函数确保在赋值时进行深拷贝,避免了指针共享的问题。 --- ### 注意事项 - **自赋值检查**:所有赋值运算符实现都应包含 `if (this != &other)` 以避免自赋值带来的问题。 - **资源释放顺序**:在重新分配资源之前,先创建新资源,再释放旧资源,以确保异常安全。 - **返回类型**:必须返回当前对象的引用,以支持链式赋值。 - **默认行为**:仅当默认赋值行为不满足需求时才需要手动重载。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值