精华内容
下载资源
问答
  • 赋值重载函数

    2018-07-05 19:48:16
    1.关于赋值运算符的重载写代码时注意以下几点:1.函数返回值要把函数返回值声明为该类型的引用,则才可以连续赋值2.函数形参把传入参数的类型声明为常量引用,可提高代码效率,原因:否则,从形参到实参会调用一次...
    1.关于赋值运算符的重载
    写代码时注意以下几点:
    1.函数返回值
    要把函数返回值声明为该类型的引用,则才可以连续赋值
    2.函数形参
    把传入参数的类型声明为 常量引用,可提高代码效率,
    原因:否则,从形参到实参会调用一次拷贝构造,且在赋值运算符函数内不改变传入对象的状态,所以在传入的引用参数前加const
    3.判断传入的参数和当前的对象(*this)是不是同一个对象
    若为同一个,一旦释放自身内存,传入参数的内存也被释放了,则找不到需要赋值的内容了
    4.分配新内存之前要释放对象自身已有的内存,否则会造成内存泄漏(之后总结)
    5在函数结束前返回对象自身的引用(*this)(这样才能连续赋值);
    代码如下
    CMyString & CMyString::operator=(const CMyString& str)
    {
         if (this == &str)
         {
              return *this;
         }
         delete mpData;
         mpData = NULL;
         int len = strlen(str.mpData);
         mpData = new char[len + 1];
         //strcpy(mpData, str.mpData);
         for (int i = 0; i <= len; ++i)
         {
               mpData[i] = str.mpData[i];
         }
         return *this;
    }

    2关于输出函数的重载问题(后续再补充)
    代码段
    friend ostream& operator<< (ostream &out, const CMyString &str)
     {
               cout << str.mpData << endl;
               return out;
      }
         

    展开全文
  • 文章目录前言一、赋值运算符重载函数是什么?二、细谈赋值运算符重载函数2.1 参数列表2.2 返回值2.3调用时机二、赋值运算符重载函数练习 前言 在介绍赋值运算符重载之前,我们先看一段代码: class Complex //定义...


    前言

    在介绍赋值运算符重载之前,我们先看一段代码:

    class Complex    //定义一个复数类
    {
    public:
        Complex (double r = 0.0,double i = 0.0) //构造函数
        {
            _real = r;
            _imag = i;
        }
        void Show()const;
    private:
        double _real,_imag;
    };
    int main()
    {
        //声明2个对象
        Complex a(10,20);
        Complex b (20,30);
        return 0;
    }
    

    此时,如果我们需要对a和b进行加法运算该咋整?一般情况下我们自然都能想到使用" + “运算符,写出一个表达式:” a + b",但是很遗憾,编译的时候必会报错,因为编译器不知道该怎么处理这个加法,这个时候就需要我们自己来编写作用在Complex类对象的"+"功能,这便引出了运算符重载

    一、赋值运算符重载函数是什么?

    赋值运算符重载是对已经有的运算符赋予多重含义,使同一个运算符作用于不同类型的数据时有着不同的含义。

    函数名为:关键字operator后面加上需要重载的运算符符号

    函数原型:

    返回值类型 operator 运算符 (形参列表)
    {
        //函数体
    }
    

    Notes:运算符重载的实质就是函数的重载:在实现的过程中,首先把指定的运算表达式转化为对运算符的调用,将运算对象转化为运算符函数的参数,然后根据参数的类型来确定需要调用的函数。

    二、细谈赋值运算符重载函数

    2.1 参数列表

    一般情况下,赋值运算符重载函数的参数是函数所在类的const类型的引用,加const的引用原因如下:

    1. 程序员不希望在函数中对已经用const修饰的值做任何修改。
    2. 加上const后,对于const和非const的参数,函数就能接受;如果不加,就只能接受非const的参数。

    加引用的原因:

    加上引用后可以有效的避免函数调用时对实参的拷贝,提高了程序的效率。

    Notes:以上的规定不是强制性规定。可以不加const,也可以没有引用,甚至参数可以不是函数所在的对象。

    2.2 返回值

    一般情况下,返回值是被赋值者的引用,即*this,原因如下:

    1. 返回*this,避免了函数的一次拷贝,提高程序效率。
    2. 返回引用还可以达到连续赋值的作用,比如"a = b = c"。如果返回类型不是引用而是返回值类型,那么在执行b = c 时候,调用赋值运算符重载函数,在函数返回的时候,会形成一个无名的临时对象,接着拷贝临时对象,然后将这个临时对象返回,但是这临时对象是一个右值,再进行a = 时候,会出错。

    2.3调用时机

    当为一个类对象赋值时,会由该对象调用该类的赋值运算符重载函数。

        MyStr str1;
        str1 = str2;
        MyStr str3 = str2;
    

    比如上述例子,定义个MyStr的类。第二个语句和第三个语句在调用函数上面是有区别的。

    MyStr str1;是str1的声明加定义,调用无参数的构造函数,所以str2 = str1时在str1已经存在的情况下用str2来为str1赋值,调用赋值运算符重载函数;而MyStr str3 = str2;调用的是拷贝构造函数。

    二、赋值运算符重载函数练习

    定义一个日期类,实现各种运算符重载:

    #include <iostream>
    #include <assert.h>
    using namespace std;
    
    class Date
    {
        friend ostream& operator<<(ostream& out,Date &d);
        friend istream& operator>>(istream& is,Date &d);
    public:
        //构造
        explicit Date (int year = 1900,int month = 1,int day = 1)
        {
            //判断参数是否合法
            if ((year >= 1900) && (month >= 1) && (day >= 1))
            {
                _year = year,_month = month,_day = day;
            }else{
                cout<<"日期非法"<<endl;
                _year = 1900,_month =  1,_day = 1;
            }
        }
        //拷贝构造
        Date (const Date &d)
        {
            _year = d._year,_month = d._month,_day = d._day;
        }
        //赋值重载函数
        Date& operator=(const Date &d);
        bool operator==(const Date &d);
        bool operator!=(const Date &d);
        bool operator>(const Date &d);
        bool operator>=(const Date &d);
        bool operator<(const Date &d);
        bool operator<=(const Date &d);
        Date operator+(int day);
        Date& operator+=(int day);
        Date operator-(int day);
        int  operator-(const Date &d);
        Date& operator-=(int day);
        Date& operator++();
        Date operator++(int);
        Date& operator--();
        Date operator--(int);
    
        //析构
        ~Date() = default;
    
    public:
        //得到某年当前月的天数
        int GetDayOfMonth(int year,int month)
        {
            assert(month > 0 && month <= 12);
            int Month_arr[13] = {0,31,29,31,30,31,30,31,31,30,31,30,31};
            int day;
            //如果不是闰年并且不是2月
            if (!(IsLeapYear()) && month == 2)
                day = Month_arr[month] - 1;
            day = Month_arr[month];
            return day;
        }
    
        //判断是不是闰年
        bool IsLeapYear()
        {
            return (_year % 4 == 0 && _year % 100 != 0) || (_year % 400 == 0);
        }
    private:
        int _year,_month,_day;
    };
    
    ostream& operator<<(ostream& out,Date &d)
    {
        out<<d._year<<"-"<<d._month<<"-"<<d._day<<endl;
        return out;
    }
    
    istream& operator>>(istream& is,Date &d)
    {
        cout<<"请输入日期:";
        is >>d._year;
        is >>d._month;
        is >>d._day;
        return is;
    
    }
    
    Date& Date::operator=(const Date &d)
    {
        if (*this != d)
        {
            _year = d._year,_month = d._month,_day = d._day;
        }
        return *this;
    }
    
    bool Date::operator==(const Date &d)
    {
        return (_year == d._year) && (_month == d._month) && (_day == d._day);
    }
    
    bool Date::operator!=(const Date &d)
    {
        return !(*this == d);
    }
    
    bool Date::operator>(const Date &d)
    {
        return (_year > d._year) || ((_year == d._year) && (_month > d._month)) || ((_year == d._year) && (_month == d._month) && (_day > d._day));
    }
    
    bool Date::operator>=(const Date &d)
    {
        return (*this == d) || (*this > d);
    }
    
    bool Date::operator<(const Date &d)
    {
        return (_year < d._year) || ((_year == d._year) && (_month < d._month)) || ((_year == d._year) && (_month == d._month) && (_day < d._day));
    }
    
    bool Date::operator<=(const Date &d)
    {
        return (*this == d) || (*this < d);
    }
    
    Date& Date::operator++()
    {
        *this = *this + 1;
        return *this;
    }
    
    Date Date::operator++(int)
    {
        Date tmp = *this;
        *this += 1;
        return tmp;
    }
    
    Date& Date::operator--()
    {
        *this -= 1;
        return *this;
    }
    
    Date Date::operator--(int)
    {
        Date tmp = *this;
        *this -= 1;
        return tmp;
    }
    
    Date Date::operator+(int day)
    {
        Date tmp = *this;
        if (day < 0)
        {
            return tmp - (-day);
        }
        tmp._day = tmp._day + day;
        while (tmp._day > GetDayOfMonth(tmp._year,tmp._month))
        {
            tmp._day = tmp._day - GetDayOfMonth(tmp._year,tmp._month);
            if (tmp._month == 12)
            {
                tmp._year++;
                tmp._month = 1;
            }else{
                tmp._month++;
            }
        }
        return tmp;
    }
    
    Date& Date::operator+=(int day)
    {
        *this = *this + day;
        return *this;
    }
    
    Date Date::operator-(int day)
    {
        Date tmp = *this;
        if (day < 0)
        {
            return tmp + (-day);
        }
        tmp._day = tmp._day - day;
        while (tmp._day <= 0)
        {
            if (tmp._month == 1)
            {
                tmp._year--;
                tmp._month = 12;
            }else{
                tmp._month = tmp._month - 1;
            }
            tmp._day = tmp._day + GetDayOfMonth(tmp._year,tmp._month);
        }
        return tmp;
    }
    
    Date& Date::operator-=(int day)
    {
        *this = *this - day;
        return *this;
    }
    
    int Date::operator-(const Date &d)
    {
        Date Max = *this;
        Date Min = d;
        int flag = 1;
        if (*this < d)
        {
            Min = *this;
            Max = d;
            flag = -1;
        }
        int day = 0;
        while (Max != Min)
        {
            --Max;
            ++day;
        }
        return flag * day;
    }
    
    
    展开全文
  • 关于赋值重载函数

    2017-03-09 16:56:32
    http://www.cnblogs.com/zpcdbky/p/5027481.html
    展开全文
  • 一、提供默认赋值运算符重载函数的时机 当程序没有显示地提供一个以本类或者本类的引用为参数的赋值运算符重载函数时,编译器会自动生成这样一个赋值运算符重载函数。#include using namespace std;class Data { ...

    一、提供默认赋值运算符重载函数的时机
    当程序没有显示地提供一个以本类或者本类的引用为参数的赋值运算符重载函数时,编译器会自动生成这样一个赋值运算符重载函数。

    #include <iostream>
    using namespace std;
    
    class Data {
    public:
        Data() {}
        Data(int _data) :data(_data)
        {
            cout << "constructor" << endl;
        }
        Data& operator = (const int _data)
        {
            cout << "operator = (const int _data)" << endl;
            data = _data;
            return *this;
        }
    private:
        int data;   
    };
    
    void main()
    {
        Data data1(1);
        Data data2, data3;
        data2 = 1;
        data3 = data2;//调用编译器提供的默认的赋值运算符重载函数
        return;
    }

    运行结果:
    这里写图片描述

    二、浅拷贝和深拷贝
    这是拷贝构造函数和赋值运算符重载函数都会涉及到的这个问题。
    所谓浅拷贝,就是说编译器提供的默认的拷贝构造函数和赋值运算符重载函数,仅仅是将对象中各个数据成员的值拷贝给另一个同一个类对象对应的数据成员。
    在深拷贝情况下,对于对象中动态成员,就不能仅仅简单地赋值,而应该重新动态分配空间。

    #include <iostream>
    #include <string>
    using namespace std;
    
    class MyStr {
    public:
        MyStr() {}
        MyStr(int _id, char *_name)
        {
            cout << "constructor" << endl;
            id = _id;
            name = new char[strlen(_name) + 1];
            strcpy_s(name,strlen(_name) + 1,_name); 
        }
        MyStr(const MyStr &str)
        {
            cout << "copy constructor" << endl;
            id = str.id;
            if (name != NULL)
                delete name;
            name = new char[strlen(str.name) + 1];
            strcpy_s(name,strlen(str.name) + 1,str.name);
        }
    
        MyStr& operator=(const MyStr& str)
        {
            cout << "operator=" << endl;
            if (this != &str)
            {
                if (name != NULL)
                    delete name;
                this->id = str.id;
                name = new char[strlen(str.name) + 1];
                strcpy_s(name,strlen(str.name) + 1,str.name);
    
                return *this;
            }
        }
        ~MyStr() 
        {
            cout << "deconstructor" << endl;
            delete name;
        }
    private:
        char *name;
        int id;
    };
    
    void main()
    {
        MyStr str1(1,"Jack");
        MyStr str2;
        str2 = str1;
        MyStr str3 = str2;
        return;
    
    }
    

    运行结果:
    这里写图片描述

    分析:
    如果将上述例子显示提供的拷贝函数注释掉,然后同样执行MyStr str3 = str2;语句,此时调用默认的拷贝构造函数,它们指向内存中的同一区域。
    这样会有两个致命错误:
    1)、str2修改name时,str3的name也会被修改;
    2)、当执行str2和str3的析构函数时,会导致同一内存区域释放两次,程序崩溃。

    所以,必须通过显示提供拷贝构造函数以避免这样的问题,如上述例子,先判断被拷贝者的name是否为空,若否,delete name,然后为name重新申请空间,再将拷贝者name中的数据拷贝到被拷贝者的name中,这样,str2.name和str3.name各自独立,避免了上面两个错误。赋值运算符重载函数也是同样的道理。

    三、赋值运算符重载函数只能是类的非静态的成员函数
    1、因为静态成员函数只能操作类的静态成员,无法操作类的非静态成员,可以参考静态成员变量和静态成员函数在C++类中的作用来进行理解;
    2、避免二义性
    当程序没有显示提供一个以本类或者本类的引用为参数的赋值运算符重载函数时,编译器会自动提供一个。现在假设C++允许友元函数定义的赋值运算符重载函数,而且以引用为参数,与此同时,编译器也提供一个默认的赋值运算符重载函数(由于友元函数不属于这个类,所以此时编译器会自动提供一个)。但是当再执行类似str2 = str1;这样的代码时,编译器就困惑了。
    为了避免这样的二义性,C++强制规定,赋值运算符重载函数只能定义为类的成员函数,这样编译器就能判断是否需要提供默认版本了。

    展开全文
  • 拷贝构造函数(对象初始化对象的过程)4.1 前言4.2 什么是拷贝构造函数4.3 拷贝构造函数的特性4.4 拷贝构造函数参数中的const是否可以去掉4.5 拷贝构造函数参数中&是否可以去掉5. 1. 类的6个默认成员函数 如果一...
  • C++赋值运算符重载函数(operator=)

    千次阅读 2018-08-13 21:41:32
      由于对c++的重载符号一直不是很理解,此处参阅一些资料给出比较详细的解释,方便读者以及自己查阅。 例1 #include&amp;amp;amp;lt;iostream&amp;amp;amp;gt; #include&amp;amp;amp;lt;cstring&...
  • 这篇文章将对C++中复制构造函数重载赋值操作符进行总结,包括以下内容: 1.复制构造函数重载赋值操作符的定义; 2.复制构造函数重载赋值操作符的调用时机; 3.复制构造函数重载赋值操作符的实现要点; 4....
  • 声明一个空的类testsize,sizeof(testsize)为1,为其声明构造函数和析构函数,依旧为1 构造函数不能使用关键字virtual,析构函数可以 一旦类中存在虚函数,就会为该类生成虚函数表,并在每一个实例中添加一个指向...
  • 陷阱重重的C++赋值重载函数operator=

    千次阅读 2014-11-12 09:34:38
    陷阱重重的C++赋值重载函数operator=,菜鸟进阶需掌握之!
  • C++编程语言中赋值运算符重载函数(operator=)介绍

    万次阅读 多人点赞 2018-06-11 18:27:00
    本文主要介绍 C++ 编程语言中赋值运算符重载函数(operator=)的相关知识,同时通过示例代码介绍赋值运算符重载函数的使用方法。 1 概述 1.1 Why 首先介绍为什么要对赋值运算符“=”进行重载。某些情况下,当我们...
  • C++ 拷贝构造函数重载赋值函数

    千次阅读 2016-03-24 15:05:10
    拷贝构造函数重载赋值=的函数可以有效防止在浅复制过程中可能对于同一片内存释放两次的问题。 然而拷贝函数重载复制=的函数很容易混淆。拷贝构造函数是在对象创建时调用的,而赋值函数只能被已经存在的对象调用...
  • 拷贝构造函数 首先从构造函数说起,在C++面向对象的设计中,每一个对象代表一个...拷贝构造函数则是为了将老对象的数据成员一一赋值给新的对象数据成员的一种构造函数,即拷贝构造函数的结果和构造函数一致,都是...
  • 目录 背景: 正文: 1、举例 2、参数解析: ...5、提供默认赋值运算符重载函数的时机 ...6、构造函数还是赋值运算符重载函数 ...7、显式提供赋值运算符重载函数的时机 ...9、赋值运算符重载函数...10、赋值运算符重载函数...
  • 拷贝函数是用在已存在对象(的各成员当前值)来创建一个相同的新对象(尚不存在,正在创建),自动调用所属类的拷贝构造函数:当说明新的类对象的同时要给他赋值另...赋值运算符重载函数要把一个已存在的对象(的各成员
  • C++中一般创建对象,拷贝或赋值的方式有构造函数,拷贝构造函数赋值函数这三种方法。下面就详细比较下三者之间的区别以及它们的具体实现 1.构造函数 构造函数是一种特殊的类成员函数,是当创建一个类的对象时,...
  • 本章主要介绍类中的编译器提供的拷贝构造函数和自定义拷贝构造函数、赋值运算符重载函数 用同类型对象初始化新对象时用到外部资源时需要调用自己定义的拷贝构造函数,防止发生浅拷贝 用同类型对象赋值给已...
  • 构造函数 #include "stdafx.h" #include using namespace std; class String { public: String() {} 类的实例化 特点: 1.函数名和类名相同; 2.没有返回值; 3.不能用const修饰。 拷贝构造函数 是特殊的构造...
  • C++赋值运算符的重载函数
  • 前言 这篇文章将对C++中复制构造函数重载赋值操作符进行总结,包括以下内容: ...我们都知道,在C++中建立一个类,这个类中肯定会包括构造函数、析构函数、复制构造函数重载赋值操作;即使在你没有明确定
  • 详解C++ 编写String 的构造函数、拷贝构造函数、析构函数赋值函数  编写类String 的构造函数、析构函数赋值函数,已知类String 的原型为: class String { public: String(const char *str = NULL); // 普通...
  • 2. 拷贝构造函数的特点(1)拷贝构造函数其实是一个构造函数重载;(2)拷贝构造函数的参数必须要用引用传参,使用传值方式会引发无穷递归调用;(3)若是没有显示定义拷贝构造函数,系统会默认缺省。缺省的拷贝...
  • 所以当用=给一个对象赋值的时候,实际调用的是=号所对应的=号函数。 分析下面的代码 #include using namespace std; class Test{ public: explicit Test(){ data = 0; } explicit Test(int d):data(d){ cout ...
  • C++ 拷贝构造函数赋值构造函数

    万次阅读 多人点赞 2019-04-06 16:43:35
    在C++中复制控制是一个比较重要的话题,主要包括复制构造函数重载赋值操作符、析构函数这三部分,这三个函数是一致的,如果类需要析构函数,则它也需要复制操作符 和 复制构造函数,这个规则被称为 C++的“三法则...
  • 现在先说说赋值运算符“=”的重载C++规定赋值运算符“=”只能重载为类的非静态成员函数,而不可以重载为类的友元函数。不能重载为类的静态成员应该比较容易理解,因为静态成员函数是属于整个类的,不是属于某个对象...
  • 首先对标准输入输出符号的重载,如果不定义为友元函数,而是定义为Class Test 类的成员函数 void operator<<(std::ostream& os); obj是Test的对象,那调用格式就成了obj<<std::cout;这样就和使用...
  • 赋值运算符重载和拷贝构造函数

    千次阅读 2017-08-02 12:13:32
    C++本质:类的赋值运算符=的重载,以及深拷贝和浅拷贝 关键词:构造函数,浅拷贝,深拷贝,堆栈(stack),堆heap,赋值运算符 摘要:  在面向对象程序设计中,对象间的相互拷贝和赋值是经常进行的操作。  如果对象...
  • 拷贝构造函数 : 1概念 拷贝构造函数只有单个形参,该形参是对本类类型对象的引用(常用const 修饰), 使用已存在的类类型的对象创建新对象时,编译器自动调用该函数。 eg: 假如 Claa A{ public:A(const A& a){...
  • php中拷贝构造函数赋值运算符重载方法, 需要的朋友可以参考下

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 165,706
精华内容 66,282
关键字:

赋值重载函数