c++运算符重载(2)-- 赋值运算符重载

首先我们前面说到c++规定,赋值运算符重载函数需要在类中定义。

赋值运算符重载函数其实就是重载=,使其可以直接对对象进行赋值运算。其实前面构造函数中已经有说过赋值构造函数的重载了。

class Human {
public:
	Human();
	Human(const char* name, int age, int salary);
	Human& operator=(const Human& man);

	string description()const;
	~Human();
private:
	char* name;
	int age;
	int salary;
};

int main(void) {
	Human man1("ABC", 28, 50000);
	Human man2;

	// man2.operator=(man1);
	man2 = man1;

	cout << man2.description() << endl;

	system("pause");

	return 0;
}

Human::Human()
{
	name = 0;
	age = 0;
	salary = 0;
}

Human::Human(const char* name, int age, int salary)
{
	/*
	  我们此处可以直接使用name指向传进来的参数,但是指向之后我们内部的name指针就指向了,
	  实参的name,这样显然是不正确的,如果外面的数据销毁,那么就会影响类内部的数据,所以
	  在类的内部我们需要有一片内存来存放传入的数据,所以需要动态开辟内存。

	  如果传入的name为空,那么就写入"未命名"
	*/
	if (!name) {           // 如果name为空
		name = "未命名";   // 此处的name为参数中的name
	}

	this->name = new char[strlen(name) + 1];   // 开辟空间, +1是因为char*末尾有字符串结束符

	strcpy_s(this->name, strlen(name) + 1, name); // 将参数中name的值拷贝到成员数据name中

	this->age = age;
	this->salary = salary;
}

Human& Human::operator=(const Human& man)
{
	/*赋值运算符重载,我们将man中的name赋值给对象的name,由于对象中name使用的是char*,无法
	自己改变空间大小,因为我们之前给name开辟内存的时候是根据传入的参数的长度开辟的,如果man
	中名字的长度比之前名字的长度长的话,直接将名字拷贝过去会导致内存溢出的,
	
	所以我们需要释放掉前面的内存,再根据赋值的值重新开辟内存,然后将值拷贝进去。此处释放也
	需要判断指针是否为空。*/

	if (this->name) {
		delete[] (this->name);
	}

	this->name = new char[strlen(man.name) + 1];
	//this->name = (char*)malloc((strlen(man.name) + 1) * sizeof(char));

	strcpy_s(this->name, strlen(man.name) + 1, man.name);

	this->age = age;
	this->salary = salary;

	return *this;
}

string Human::description() const
{
	stringstream ret;

	ret << "姓名: " << name << " 年龄: " << age << " 薪水:" << salary << endl;

	return ret.str();
}

Human::~Human()
{
	/*
	  代码技巧:  我们在析构函数中释放空间的时候,需要先判断是否有这个空间(也就是对应指针是否
	  为空)。非空,我们才释放空间,如果本来就是空的再释放就会出问题
	*/

	if (name) {   // 如果name非空释放空间
		delete[] name; 
	}
}

代码分析: 

1.  首先在代码中,Human类中name我们使用的是char*类型的字符串。 和string类型的字符串不同,它是不会自己开辟内存的。 

所以在有参构造函数中,我们需要先给name根据传入参数的大小开辟内存,然后再使用字符串拷贝函数将字符串拷贝到类的name中。

2.  既然上面动态开辟了内存,那么我们就需要在类内部的析构函数释放我们申请的内存。

    在释放之前我们得先判断一下,对应的指针是否为空,如果为空那么就不能再对齐释放,如果不为空再释放空间。 

3.  Human& operator=(const Human& human);  是运算符重载的函数原型。

1)返回一个Human& 是为了可以连续赋值。  

4.  在赋值运算符重载的函数中,因为我们在对象构造的时候,根据传入的数据来开辟对应指针的内存,所以这样就会导致一个问题:如果传入对象的name占用内存大于被赋值的对象的name的内存,就会发生内存溢出。

所以,我们需要先释放掉原来开辟的内存(这时候也需要判断是否对应的指针是否为空,和上面原因一样),然后再根据参数对象的name大小开辟内存,再将数据拷贝到当中去。

5.   我们之所以需要手动开辟内存,是因为我们使用的是C语言的字符串,如果使用c++中的string就不需要了,直接将参数的name赋值就行,this->name = man.name;

6.  开辟内存时的,我们使用strlen(name)+1,+1的原因是因为C语言的字符串以\0结尾,strlen()求得的是字符串的长度,不包括字符串结束符,所以+1是为了容纳字符串结束符。

 

 

你可能感兴趣的:(c++,开发语言)