首页 > 其他分享 >32.赋值运算符重载

32.赋值运算符重载

时间:2022-10-12 21:12:58浏览次数:44  
标签:32 运算符 stu pName Student 重载 mAge 赋值

1.赋值(=)运算符重载

  赋值符常常初学者的混淆。这是毫无疑问的,因为’=’在编程中是最基本的运算符,可以进行赋值操作,也能引起拷贝构造函数的调用。

class Person{
	friend ostream& operator<<(ostream& os,const Person& person){
		os << "ID:" << person.mID << " Age:" << person.mAge << endl;
		return os;
	}
public:
	Person(int id,int age){
		this->mID = id;
		this->mAge = age;
	}
	//重载赋值运算符
	Person& operator=(const Person& person){
		this->mID = person.mID;
		this->mAge = person.mAge;
		return *this;
	}
private:
	int mID;
	int mAge;
};

//1. =号混淆的地方
void test01(){
	Person person1(10, 20);
	Person person2 = person1; //调用拷贝构造
	//如果一个对象还没有被创建,则必须初始化,也就是调用构造函数
	//上述例子由于person2还没有初始化,所以会调用构造函数
	//由于person2是从已有的person1来创建的,所以只有一个选择
	//就是调用拷贝构造函数
	person2 = person1; //调用operator=函数
	//由于person2已经创建,不需要再调用构造函数,这时候调用的是重载的赋值运算符
}
//2. 赋值重载案例
void test02(){
	Person person1(20, 20);
	Person person2(30, 30);
	cout << "person1:" << person1;
	cout << "person2:" << person2;
	person2 = person1;
	cout << "person2:" << person2;
}
//常见错误,当准备给两个相同对象赋值时,应该首先检查一下这个对象是否对自身赋值了
//对于本例来讲,无论如何执行这些赋值运算都是无害的,但如果对类的实现进行修改,那么将会出现差异;
//3. 类中指针
class Person2{
	friend ostream& operator<<(ostream& os, const Person2& person){
		os << "Name:" << person.pName << " ID:" << person.mID << " Age:" << person.mAge << endl;
		return os;
	}
public:
	Person2(char* name,int id, int age){
		this->pName = new char[strlen(name) + 1];
		strcpy(this->pName, name);
		this->mID = id;
		this->mAge = age;
	}
#if 1
	//重载赋值运算符
	Person2& operator=(const Person2& person){

		//注意:由于当前对象已经创建完毕,那么就有可能pName指向堆内存
		//这个时候如果直接赋值,会导致内存没有及时释放
		if (this->pName != NULL){
			delete[] this->pName;
		}

		this->pName = new char[strlen(person.pName) + 1];
		strcpy(this->pName,person.pName);
		this->mID = person.mID;
		this->mAge = person.mAge;
		return *this;
	}
#endif
	//析构函数
	~Person2(){
		if (this->pName != NULL){
			delete[] this->pName;
		}
	}
private:
	char* pName;
	int mID;
	int mAge;
};

void test03(){
	Person2 person1("John",20, 20);
	Person2 person2("Edward",30, 30);
	cout << "person1:" << person1;
	cout << "person2:" << person2;
	person2 = person1;
	cout << "person2:" << person2;
}

为什么operator=返回一个reference to *this ?

为了实现连续赋值,赋值操作符必须返回一个引用指向操作符的左侧实参。这是你为class实现赋值操作符必须遵循的协议。这个协议不仅适用于标准的赋值形式,也适用于+=、-=、*=等等。
   注意,这只是一个协议,并无请执行。如果不遵循它,可能代码一样通过编译。然而这份协议被所有内置类型和标准程序库所提供的类型如string、vector等所遵守。因此除非你有一个标新立异的好理由,不然还是随众吧。
class Person{
	friend ostream& operator<<(ostream& os, const Person& person){
		os << "ID:" << person.mID << " Age:" << person.mAge << endl;
		return os;
	}
public:
	Person(int id, int age){
		this->mID = id;
		this->mAge = age;
	}
	//重载赋值运算符
	Person operator=(const Person& person){
		this->mID = person.mID;
		this->mAge = person.mAge;
		return *this;
	}
	//重载赋值运算符
	Person operator=(int x){
		this->mID = x;
		this->mAge = x;
		return *this;
	}
private:
	int mID;
	int mAge;
};

void test(){
	Person person1(20, 20);
	Person person2(30, 30);
	cout << "person1:" << person1;
	cout << "person2:" << person2;
//由于person2 = person1返回的是临时对象,所以赋值为10并没有改变person2对象
	(person2 = person1) = 10;
	cout << "person2:" << person2;
}
 如果没有重载赋值运算符,编译器会自动创建默认的赋值运算符重载函数。行为类似默认拷贝构造,进行简单值拷贝。


2.视频内容

程序1:

#pragma warning(disable:4996)
//2022年10月12日20:09:55
#include <iostream>
using namespace std;

class Maker
{
public:
    Maker()
    {
        id = 0;
        age = 0;
    }
    Maker(int id, int age)
    {
        this->id = id;
        this->age = age;
    }
public:
    int id;
    int age;
};

void test()
{
    Maker m1(10, 20);
    Maker m2;

    m2 = m1;//赋值操作
    //默认的赋值操作运算符重载函数进行了简单的赋值操作
    cout << m2.id << " " << m2.age << endl;
}

int main()
{
    test();
    system("pause");
    return EXIT_SUCCESS;
}

输出结果:

10 20
请按任意键继续. . .

程序2:

#pragma warning(disable:4996)
//2022年10月12日20:09:55
#include <iostream>
using namespace std;

class Student
{
public:
    Student(const char *name)
    {
        pName = new char[strlen(name) + 1];
        strcpy(pName, name);
    }
    //防止浅拷贝
    Student(const Student &stu)
    {
        pName = new char[strlen(stu.pName) + 1];
        strcpy(pName, stu.pName);
    }
    //重写赋值运算符重载函数
    Student &operator=(const Student &stu)
    {
        //1.不能确定this指向的空间是否能装下stu中的数据,所以先释放this指向的空间
        if( this->pName != NULL )
        {
            delete[] this->pName;
            this->pName = NULL;
        }

        //2.申请堆区空间,大小由stu决定
        this->pName = new char[strlen(stu.pName) + 1];
        //3.拷贝数据
        strcpy(this->pName, stu.pName);

        //4.返回对象本身
        return *this;
    }
    ~Student()
    {
        if( pName != NULL )
        {
            delete[] pName;
            pName = NULL;
        }
    }

    void printStudent()
    {
        cout << "Name:" << pName << endl;
    }
public:
    char *pName;
};

void test02()
{
    Student s1("悟空");
    Student s2("小林");

    s1 = s2;//赋值操作
    s1.printStudent();
    s2.printStudent();

    //复数运算才不会出错
    //s1 = s2 = s3;
}

int main()
{
    test02();
    system("pause");
    return EXIT_SUCCESS;
}

输出结果:

Name:小林
Name:小林
请按任意键继续. . .

程序3:

#pragma warning(disable:4996)
//2022年10月12日20:09:55
#include <iostream>
using namespace std;

class Student
{
public:
    Student(const char *name)
    {
        pName = new char[strlen(name) + 1];
        strcpy(pName, name);
    }
    //防止浅拷贝
    Student(const Student &stu)
    {
        pName = new char[strlen(stu.pName) + 1];
        strcpy(pName, stu.pName);
    }
    //重写赋值运算符重载函数
    Student &operator=(const Student &stu)
    {
        //1.不能确定this指向的空间是否能装下stu中的数据,所以先释放this指向的空间
        if( this->pName != NULL )
        {
            delete[] this->pName;
            this->pName = NULL;
        }

        //2.申请堆区空间,大小由stu决定
        this->pName = new char[strlen(stu.pName) + 1];
        //3.拷贝数据
        strcpy(this->pName, stu.pName);

        //4.返回对象本身
        return *this;
    }
    ~Student()
    {
        if( pName != NULL )
        {
            delete[] pName;
            pName = NULL;
        }
    }

    void printStudent()
    {
        cout << "Name:" << pName << endl;
    }
public:
    char *pName;
};

//赋值运算符重载中为什么要返回引用
void test03()
{
    Student s1("a");
    Student s2("b");
    Student s3("c");

    s1 = s2 = s3;//s3赋值s2,s2赋值给s1

    cout << &(s2 = s3) << endl;
    cout << &s2 << endl;
    //如果返回的是值,s2=s3这个表达式会产生一个新的对象
    //s1=s2=s3,赋值运算符本来的寓意,是s3赋值s2,s2赋值给s1
    //也就是说s2=s3这个表达式要返回s2这个对象
}

int main()
{
    test03();
    system("pause");
    return EXIT_SUCCESS;
}

输出结果:

000000ABA4FBF6F8
000000ABA4FBF6F8
请按任意键继续. . .

标签:32,运算符,stu,pName,Student,重载,mAge,赋值
From: https://www.cnblogs.com/codemagiciant/p/16785976.html

相关文章

  • 实验1c语言开发环境使用和数据类型,运算符和表达式
    1.试验任务1(1)在垂直方向上打印两个字符小人的源代码,以及运行结果截图 \\在垂直方向上打印两个字符小人#include<stdio.h>intmain(){printf("o\n");pr......
  • float32 和float16互转
    //intmain()//{//inti=0;//floatfVal=-255.123456789;//char*pChar;//pChar=(char*)&fVal;////for(i=0;i<4;i++)//{/......
  • win32api函数列表与MFC Socket文档地址
    ​​https://docs.microsoft.com/zh-cn/windows/win32/winsock/winsock-functions​​​​https://docs.microsoft.com/en-us/cpp/mfc/windows-sockets-in-mfc?view=msvc-16......
  • java重写(Override)&重载
    /***obj_1*Java继承*动物类*/publicclassAnimal{privateStringname;privateintid;publicAnimal(StringmyName,intmyid){name=my......
  • 如何查看windows 2003系统版本是32位还是64位
    https://zhidao.baidu.com/question/1383192132920330300.html1、右击我的电脑-属性页面一般都有。2、遇到了属性页面没有信息的,使用Windows内置命令systeminfo查看系统......
  • esp32-lvgl-ST7796+GT911
    1、st7789在lvgl配置菜单中使用ILI9481的驱动,如果使用st7789的驱动会出现显示颜色不正确,用ili9481的就可以2、gt911的驱动文件需要修改,修改gt911.c文件中60行,取消错误后的......
  • 【C语言】赋值操作符、单目操作符、自增自减运算符。
    ......
  • 第二章 运算符
    第二章运算符计算运算符操作符1.1运算符分类运算符(operator)也被称为操作符,是用于实现赋值、比较和执行算数运算等功能的符号。算数运算符递增和递减运算符比较运......
  • 困难-632. 最小区间
    设置n个哨兵,n为数组nums的长度,每个哨兵初始指向为0不停的计算最小和最大,最小的哨兵指针加1,一直到结束你有 k 个非递减排列的整数列表。找到一个最小区间,使得 k 个......
  • CF1329A Dreamoon Likes Coloring 题解
    提供一个简短的题解:首先如果所有长度加起来还不到\(n\)直接无解。可以直接贪心,把第\(i\)条线段的右端点放在\(n-i+1\)这个位置,就可以最省长度(只占一个点)而且不会遗......