C++编程语言中赋值运算符重载函数(operator=)的使用

目录
  • 1 概述
    • 1.1 Why
  • 2 示例代码
    • 2.1 示例代码1
    • 2.2 示例代码2
  • 3 总结

本文主要介绍 C++ 编程语言中赋值运算符重载函数(operator=)的相关知识,同时通过示例代码介绍赋值运算符重载函数的使用方法。

1 概述

1.1 Why

首先介绍为什么要对赋值运算符“=”进行重载。某些情况下,当我们编写一个类的时候,并不需要为该类重载“=”运算符,因为编译系统为每个类提供了默认的赋值运算符“=”,使用这个默认的赋值运算符操作类对象时,该运算符会把这个类的所有数据成员都进行一次赋值操作。例如有如下类:

class A
{
public:
    int a;
    int b;
    int c;
};

对这个类的对象进行赋值时,使用默认的赋值运算符是没有问题的。

示例代码内容如下:

#include <iostream>

using namespace std;

class ClassA
{
public:
    int a;
    int b;
    int c;
};

int main()
{
    ClassA obj1;
    obj1.a = 1;
    obj1.b = 2;
    obj1.c = 3;

    ClassA obj2;
    obj2 = obj1;

    cout << "obj2.a is: " << obj2.a << endl;

    return 0;
}
 

编译并执行上述代码,结果如下:

通过上述结果能够知道:通过使用系统默认的赋值运算符“=”,可以让对象 obj2 中的所有数据成员的值与对象 obj1 相同。这种情况下,编译系统提供的默认赋值运算符可以正常使用。

但是,在下面的示例中,使用编译系统提供的默认赋值运算符,就会出现问题了。

示例代码内容如下:

#include <iostream>
#include <string.h>

using namespace std;

class ClassA
{
public:
    ClassA()
    {

    }

    ClassA(const char* pszInputStr)
    {
        pszTestStr = new char[strlen(pszInputStr) + 1];
        strncpy(pszTestStr, pszInputStr, strlen(pszInputStr) + 1);
    }
    virtual ~ClassA()
    {
        delete pszTestStr;
    }
public:
    char* pszTestStr;
};

int main()
{
    ClassA obj1("liitdar");

    ClassA obj2;
    obj2 = obj1;

    cout << "obj2.pszTestStr is: " << obj2.pszTestStr << endl;
    cout << "addr(obj1.pszTestStr) is: " << &obj1.pszTestStr << endl;
    cout << "addr(obj2.pszTestStr) is: " << &obj2.pszTestStr << endl;

    return 0;
}

编译并运行上述代码,结果如下:

上述错误信息表明:当对象 obj1 和 obj2 进行析构时,由于重复释放了同一块内存空间,导致程序崩溃报错。在这种情况下,就需要我们重载赋值运算符“=”了。

2 示例代码

2.1 示例代码1

我们修改一下前面出错的示例代码,编写一个包含赋值运算符重载函数的类,修改后的代码内容如下:

#include <iostream>
#include <string.h>

using namespace std;

class ClassA
{
public:
    ClassA()
    {

    }
    ClassA(const char* pszInputStr)
    {
        pszTestStr = new char[strlen(pszInputStr) + 1];
        strncpy(pszTestStr, pszInputStr, strlen(pszInputStr) + 1);
    }
    virtual ~ClassA()
    {
        delete pszTestStr;
    }
    // 赋值运算符重载函数
    ClassA& operator=(const ClassA& cls)
    {
        // 避免自赋值
        if (this != &cls)
        {
            // 避免内存泄露
            if (pszTestStr != NULL)
            {
                delete pszTestStr;
                pszTestStr = NULL;
            }

            pszTestStr = new char[strlen(cls.pszTestStr) + 1];
            strncpy(pszTestStr, cls.pszTestStr, strlen(cls.pszTestStr) + 1);
        }

        return *this;
    }

public:
    char* pszTestStr;
};

int main()
{
    ClassA obj1("liitdar");

    ClassA obj2;
    obj2 = obj1;

    cout << "obj2.pszTestStr is: " << obj2.pszTestStr << endl;
    cout << "addr(obj1.pszTestStr) is: " << &obj1.pszTestStr << endl;
    cout << "addr(obj2.pszTestStr) is: " << &obj2.pszTestStr << endl;

    return 0;
}
 

编译并运行上述代码,结果如下:

通过上述结果能够看到,利用赋值运算符重载函数,解决了对象赋值时,析构函数多次释放同一块内存空间的问题。

对于上述代码,有以下几点需要说明:

当为一个类的对象赋值(可以用本类对象为其赋值,也可以用其它类型的值为其赋值)时,该对象(如本例的 obj2)会调用该类的赋值运算符重载函数,进行具体的赋值操作。如上述代码中的“obj2 = obj1;”语句,用 obj1 为 obj2 赋值,则会由 obj2 调用 ClassA 类的赋值运算符重载函数;

下方语句和语句“ClassA obj2 = obj1;”在调用函数上是有区别的:前者第一句是对象 obj2 的声明及定义,调用类 ClassA 的无参构造函数,所以“obj2 = obj1;”一句是在对象 obj2 已经存在的情况下,用 obj1 来为 obj2 赋值,调用的是赋值运算符重载函数;而后者,是用 obj1 来初始化 obj2,调用的是拷贝构造函数。拷贝构造函数的语句样式为“ClassA(const ClassA& cls)”,关于拷贝构造函数的详细内容,请参考相关内容,此处不展开介绍;

ClassA obj2;
obj2 = obj1;

当程序没有显式地提供一个以“本类或本类的引用”为参数的赋值运算符重载函数时,编译器会自动生成一个默认的赋值运算符重载函数(即默认赋值运算符)。

2.2 示例代码2

示例代码内容如下:

#include<iostream>
#include<string>

using namespace std;

class Data
{
private:
    int data;

public:
    // 构造函数
    Data()
    {
    };
    // 构造函数
    Data(int _data):data(_data)
    {
        cout << "This is constructor" << endl;
    }
    // 赋值运算符重载函数
    Data& operator=(const int _data)
    {
        cout << "This is operator=(int _data)" << endl;
        data = _data;

        return *this;
    }
};

int main()
{
    // 调用构造函数
    Data data1(1);
    Data data2, data3;
    // 调用赋值运算符重载函数
    data2 = 1;
    // 调用默认的赋值运算符重载函数
    data3 = data2;

    return 0;
}

编译并执行上述代码,结果如下:

上述结果表明:“data2 = 1;”语句调用了我们提供的以 int 型参数(而非本类或本类的引用)为形参的赋值运算符重载函数;而“data3 = data2;”的成功执行,说明该语句调用了编译器提供的默认的赋值运算符重载函数。

如果将上述代码中赋值运算符重载函数去掉,重新编译执行,结果如下:

上述结果说明,当用一个非类 A 的值(如上面的 int 类型值)为类 A 的对象赋值时:

  • 如果检测到构造函数和赋值运算符重载函数同时存在,则会优先调用赋值运算符重载函数;
  • 如果只检测到构造函数,就会调用构造函数。

3 总结

综合本文内容,可以知道针对以下情况,需要显式地提供赋值运算符重载函数(即自定义赋值运算符重载函数):

  • 用非类 A 类型的值为类 A 的对象赋值时(当然,这种情况下我们也可以不提供相应的赋值运算符重载函数,而只提供相应的构造函数,如更改后的示例代码2);
  • 用类 A 类型的值为类 A 的对象赋值,且类 A 的数据成员中含有指针的情况下,必须显式提供赋值运算符重载函数(如示例代码1)。

到此这篇关于C++编程语言中赋值运算符重载函数(operator=)介绍的文章就介绍到这了,更多相关C++ 赋值运算符重载函数内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++ 类的赋值运算符''=''重载的方法实现

    什么类需要重载赋值运算符 先来看一个普通类的直接赋值. #include <iostream> using namespace std; class person{ int age; public: person(const int& a=10):age(a){} //构造函数 ~person(); //析构函数 void showAdd(); //打印age的地址 }; person::~person(){cout<<"析构\n";} void per

  • 简单了解C++语言中的二元运算符和赋值运算符

    二元运算符 下表显示可重载的运算符的列表. 可重新定义的二进制运算符 运算符 名称 , 逗号 != 不相等 % 取模 %= 取模/赋值 & 按位"与" && 逻辑"与" &= 按位"与"/赋值 * 乘法 *= 乘法/赋值 + 添加 += 加法/赋值 – 减法 –= 减法/赋值 < 小于 << 左移 <<= 左移/赋值 <= 小于或等于 = 赋值 == 相等 > 大于 >

  • 详解C++语言中的加法运算符与赋值运算符的用法

    加法运算符:+ 和 - 语法 expression + expression expression – expression 备注 相加运算符为: 加 (+) 减 (–) 这些二进制运算符具有从左至右的关联性. 相加运算符采用算术或指针类型的操作数.加法 (+) 运算符的结果是操作数之和.减法 (–) 运算符的结果是操作数之差.如果一个操作数是指针或两个操作数都是指针,则它们必须是指向对象的指针,而不是指向函数的指针.如果两个操作数都是指针,则结果没有意义,除非它们是指向同一数组中的对象的指针.

  • C++中赋值运算符与逗号运算符的用法详解

    赋值运算符 赋值符号"="就是赋值运算符,它的作用是将一个数据赋给一个变量.如"a=3"的作用是执行一次赋值操作(或称赋值运算).把常量3赋给变量a.也可以将一个表达式的值赋给一个变量. 赋值过程中的类型转换 如果赋值运算符两侧的类型不一致,但都是数值型或字符型时,在赋值时会自动进行类型转换. 1)  将浮点型数据(包括单.双精度)赋给整型变量时,舍弃其小数部分. 2)  将整型数据赋给浮点型变量时,数值不变,但以指数形式存储到变量中. 3) 将一个double型数

  • 详解C++ 拷贝构造函数和赋值运算符

    本文主要介绍了拷贝构造函数和赋值运算符的区别,以及在什么时候调用拷贝构造函数.什么情况下调用赋值运算符.最后,简单的分析了下深拷贝和浅拷贝的问题. 拷贝构造函数和赋值运算符 在默认情况下(用户没有定义,但是也没有显式的删除),编译器会自动的隐式生成一个拷贝构造函数和赋值运算符.但用户可以使用delete来指定不生成拷贝构造函数和赋值运算符,这样的对象就不能通过值传递,也不能进行赋值运算. class Person { public: Person(const Person& p) = dele

  • C++赋值运算符

    C++当中允许类对象赋值,这是通过默认的重载赋值运算符实现的,它的原型如下: Class_name & Class_name::operator=(const Class_name &); 它接受并返回一个指向类对象的引用. 将已有的对象赋给另一个对象时,将会使用重载的赋值运算符: StringBad headline1("Celery"); StringBad knot; knot = headline1; // 调用赋值运算符 如果是对象初始化的过程,则不一定会使用

  • 详解C++中对构造函数和赋值运算符的复制和移动操作

    复制构造函数和复制赋值运算符 从 C++ 11 中开始,该语言支持两种类型的分配:复制赋值和移动赋值. 在本文中,"赋值"意味着复制赋值,除非有其他显式声明. 赋值操作和初始化操作都会导致对象被复制. 赋值:在将一个对象的值赋给另一个对象时,第一个对象将复制到第二个对象中. 因此, Point a, b; ... a = b; 导致 b 的值被复制到 a 中. 初始化:在以下情况下将进行初始化:声明新对象.参数通过值传递给函数或值通过值从函数返回. 您可以为类类型的对象定义"

  • 详解c/c++赋值函数(重载=号运算符)

    首先c++里的各种运算符都是用函数实现的,比如=,就等号函数. 所以当用=给一个对象赋值的时候,实际调用的是=号所对应的=号函数. 分析下面的代码 #include <iostream> using namespace std; class Test{ public: explicit Test(){ data = 0; } explicit Test(int d):data(d){ cout << "C:" << this << &qu

  • C++编程语言中赋值运算符重载函数(operator=)的使用

    目录 1 概述 1.1 Why 2 示例代码 2.1 示例代码1 2.2 示例代码2 3 总结 本文主要介绍 C++ 编程语言中赋值运算符重载函数(operator=)的相关知识,同时通过示例代码介绍赋值运算符重载函数的使用方法. 1 概述 1.1 Why 首先介绍为什么要对赋值运算符“=”进行重载.某些情况下,当我们编写一个类的时候,并不需要为该类重载“=”运算符,因为编译系统为每个类提供了默认的赋值运算符“=”,使用这个默认的赋值运算符操作类对象时,该运算符会把这个类的所有数据成员都进行一次

  • 解析C++中不能重载为友元函数的四个运算符

    C++规定有四个运算符 =, ->, [], ()不可以是全局域中的重载(即不能重载为友员函数),这是为什么呢?现在先说说赋值运算符"="的重载C++规定赋值运算符"="只能重载为类的非静态成员函数,而不可以重载为类的友元函数.不能重载为类的静态成员应该比较容易理解,因为静态成员函数是属于整个类的,不是属于某个对象的,它只能去操作类静态数据成员.而赋值运算符"="是基于对象操作的.那么为什么赋值运算符不可以重载为类的友元函数?像同样都是双目

  • C++中const用于函数重载的示例代码

    常成员函数和非常成员函数之间的重载 首先先回忆一下常成员函数 声明:<类型标志符>函数名(参数表)const: 说明: (1)const是函数类型的一部分,在实现部分也要带该关键字. (2)const关键字可以用于对重载函数的区分. (3)常成员函数不能更新类的成员变量,也不能调用该类中没有用const修饰的成员函数,只能调用常成员函数. (4)非常量对象也可以调用常成员函数,但是如果有重载的非常成员函数则会调用非常成员函数. 重载看例子: #include<iostream> u

  • 详解C++ 重载运算符和重载函数

    C++ 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重载. 重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是它们的参数列表和定义(实现)不相同. 当您调用一个重载函数或重载运算符时,编译器通过把您所使用的参数类型与定义中的参数类型进行比较,决定选用最合适的定义.选择最合适的重载函数或重载运算符的过程,称为重载决策. C++ 中的函数重载 在同一个作用域内,可以声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数.类型或

  • C++中运算符重载详解及其作用介绍

    目录 概述 函数重载 运算符重载 C++ 的运算符 重载运算符的规则 成员函数实现 Complex 加法 运算符重载的方法 多种实现方法 实现 operator+= 三种运算符重载函数 成员函数实现 友元函数实现 输出结果 重载单元运算符 例子 重载二元运算符 例子 重载 I/O 插入运算符 << 提取运算符 >> 总结 概述 运算符重载 (Operator Overloading) 函数重载 重载: 将同一名字重新赋予新的含义. 函数重载: 对一个函数赋予新的含义, 使之实现新功

  • Objective-C中的重载和重写详解

    Objective-C 重载和重写 首先,Objective-C中不完全支持重载,网上很多人要么将重载和重写搞混,要么说OC不支持重载(当然按照重载严格定义说OC不支持重载也没错),事实上OC支持参数个数不同的函数重载. 问题: Objective-C和Swift中有重载吗? Swift中有重载,但Objective-C中基本不支持重载. 展开: 重载.重写和隐藏三者在编程语言中的定义 重载(overload):函数名相同,函数的参数列表不同(包括参数个数和参数类型),至于返回类型可同可不同.重

  • C++中的friend函数详细解析

    为什么要使用友元函数 在实现类之间数据共享时,减少系统开销,提高效率.如果类A中的函数要访问类B中的成员(例如:智能指针类的实现),那么类A中该函数要是类B的友元函数.具体来说:为了使其他类的成员函数直接访问该类的私有变量.即:允许外面的类或函数去访问类的私有变量和保护变量,从而使两个类共享同一函数. 实际上具体大概有下面两种情况需要使用友元函数:(1)运算符重载的某些场合需要使用友元.(2)两个类要共享数据的时候. 使用友元函数的优缺点 优点:能够提高效率,表达简单.清晰. 缺点:友元函数破环

  • 详解C++编程中的重载流插入运算符和流提取运算符

    C++的流插入运算符"<<"和流提取运算符">>"是C++在类库中提供的,所有C++编译系统都在类库中提供输入流类istream和输出流类ostream.cin和cout分别是istream类和ostream类的对象.在类库提供的头文件中已经对"<<"和">>"进行了重载,使之作为流插入运算符和流提取运算符,能用来输出和输入C++标准类型的数据.因此,凡是用"cout&

  • C++实践分数类中运算符重载的方法参考

    [项目-分数类中的运算符重载] (1)实现分数类中的运算符重载,在分数类中可以完成分数的加减乘除(运算后再化简).比较(6种关系)的运算. class CFraction { private: int nume; // 分子 int deno; // 分母 public: //构造函数及运算符重载的函数声明 }; //重载函数的实现及用于测试的main()函数 (2)在(1)的基础上,实现分数类中的对象和整型数的四则运算.分数类中的对象可以和整型数进行四则运算,且运算符合交换律.例如:CFrac

随机推荐