美文网首页
C++ 运算符重载(二)(11)

C++ 运算符重载(二)(11)

作者: maskerII | 来源:发表于2022-06-24 09:13 被阅读0次

    1. 赋值运算符重载

    1. 编译器默认给类提供了一个默认的赋值运算符重载函数
    2. 默认的赋值运算符重载函数做了简单的赋值操作
    3. 当类有成员指针时,并且在构造函数中申请堆区空间,在析构函数中释放堆区空间,如果不重写赋值运算符重载函数,会导致内存泄漏,和同一块堆区空间被释放多次
    4. 赋值运算符中 为什么要返回引用 如果赋值运算符返回值,在复数运算时违背了它本来的寓意
    class Maker1
    {
    public:
        int id;
        int age;
    
    public:
        void printMaker1()
        {
            cout << "id = " << this->id << " age = " << this->age << endl;
        }
    
    public:
        Maker1()
        {
        }
        Maker1(int id, int age)
        {
            this->id = id;
            this->age = age;
        }
    };
    
    void test01()
    {
        Maker1 m1(18, 20);
        Maker1 m2;
        m2 = m1; // 赋值操作  默认的赋值运算符重载函数做了简单的赋值操作
    
        m2.printMaker1();
    }
    
    
    class Student
    {
    public:
        char *pName;
    
    public:
        void printStudent()
        {
            cout << "name =  " << this->pName << endl;
        }
    
    public:
        Student(const char *name)
        {
            cout << "有参构造函数" << endl;
            // 申请堆区空间
            this->pName = new char[strlen(name) + 1];
            // 拷贝数据
            strcpy(this->pName, name);
        }
        // 防止浅拷贝
        Student(const Student &m)
        {
            cout << "拷贝构造函数" << endl;
            // 申请堆区空间
            pName = new char[strlen(m.pName) + 1];
            // 拷贝数据
            strcpy(pName, m.pName);
        }
        // 重写赋值运算符重载
        // 返回引用
        Student &operator=(const Student &stu)
        {
            cout << "赋值运算" << endl;
            // 不能确定this->pName指向的空间是否能装上stu中的数据,所以先释放this->pName指向的空间,再申请空间,拷贝数据,最后返回*this
            // 1.删除原来的空间
            if (this->pName != NULL)
            {
                delete[] this->pName;
                this->pName = NULL;
            }
            // 2.申请空间
            this->pName = new char[strlen(stu.pName) + 1];
            // 3.拷贝数据
            strcpy(this->pName, stu.pName);
            // 4.返回对象本身
            return *this;
        }
    
        ~Student()
        {
            cout << "析构函数" << endl;
            if (pName != NULL)
            {
                delete[] pName;
                pName = NULL;
            }
        }
    };
    
    void test02()
    {
        Student m1("Emily");
        Student m2 = m1; // 拷贝构造
        m2.printStudent();
    
        cout << "============== 1" << endl;
        Student m3("悟空");
        m3 = m1; // 赋值元算符
        m3.printStudent();
    
        cout << "============== 2" << endl;
    
        Student m4 = m3 = m1;
        m3.printStudent();
    
        cout << "------------- 3" << endl;
    }
    

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

    为了实现连续赋值,赋值操作符必须返回一个引用指向操作符的左侧实参。这是你为class实现赋值操作符必须遵循的协议。这个协议不仅适用于标准的赋值形式,也适用于+=、-=、*=等等。

    2. 关系运算符重载 == !=

    // == !=
    class Maker
    {
    private:
        int id;
        int age;
    
    public:
        Maker(int id, int age);
        bool operator==(Maker &m2);
        bool operator!=(Maker &m2);
    };
    
    Maker::Maker(int id, int age)
    {
        this->id = id;
        this->age = age;
    }
    
    bool Maker::operator==(Maker &m2)
    {
        if (this->id == m2.id && this->age == m2.age)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    
    bool Maker::operator!=(Maker &m2)
    {
        if (this->id != m2.id || this->age != m2.age)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    
    void test01()
    {
        Maker m1(18, 20);
        Maker m2(25, 56);
    
        if (m1 == m2)
        {
            cout << "真" << endl;
        }
        else
        {
            cout << "假" << endl;
        }
    
        if (m1 != m2)
        {
            cout << "真" << endl;
        }
        else
        {
            cout << "假" << endl;
        }
    }
    

    3. 前置加加和后置加加运算符重载

    class Maker
    {
    public:
        int age;
    
    public:
        Maker(int age)
        {
            this->age = age;
        }
        // 前置加加
        Maker &operator++()
        {
            cout << "前置加加" << endl;
            ++this->age;
            return *this;
        }
        // 后置加加
        // 前置加加和后置加加以是否有占位符区分
        Maker operator++(int) // 占位参数必须是int
        {
            // 后置加加 先返回 再加加
            cout << "后置加加" << endl;
            Maker tmp(*this); // 拷贝构造
            ++this->age;
            return tmp;
        }
    };
    
    // << 运算符重载
    // 注意 此处 形参Maker m,如果使用引用,cout << m1++ << endl 会出错
    // 原因 m1++ 后置加加是返回了一个临时对象,临时对象引用会出错
    ostream &operator<<(ostream &os, Maker m)
    {
        cout << m.age << endl;
        return os;
    }
    
    void test01()
    {
        Maker m1(1);
        cout << m1 << endl; // 1
    
        cout << ++m1 << endl; // 2
    
        cout << (m1++).age << endl; // 2
    
        cout << m1++ << endl; // 3
    
        cout << m1 << endl; // 4
    }
    

    4. 数组下标运算符重载[]

    
    class MyArray
    {
    public:
        // 头插
        void PushFront(int val)
        {
            if (mCapacity == mSize)
            {
                return;
            }
    
            // 数据往后移
            for (int i = mSize - 1; i >= 0; I--)
            {
                pArray[i + 1] = pArray[I];
            }
    
            pArray[0] = val;
    
            mSize++;
        }
        // 尾插
        void PushBack(int val)
        {
            if (mCapacity == mSize)
            {
                return;
            }
    
            pArray[mSize] = val;
    
            mSize++;
        }
        // 头删
        void popFront()
        {
            if (mSize == 0)
            {
                return;
            }
            // 后面的数往前面移动来覆盖第一个元素
            for (int i = 0; i < mSize - 1; I++)
            {
                pArray[i] = pArray[i + 1];
            }
    
            mSize--;
        }
        // 尾删
        void popBack()
        {
            if (mSize == 0)
            {
                return;
            }
            mSize--;
        }
    
        // 获取数组元素的个数
        int Size()
        {
            return mSize;
        }
    
        // 获取数组的容量
        int Capacity()
        {
            return mCapacity;
        }
    
        // 指定位置插入元素
        void Insert(int pos, int val)
        {
            if (mCapacity == mSize)
            {
                return;
            }
    
            if (pos < 0 || pos > mSize - 1)
            {
                return;
            }
    
            for (int i = mSize - 1; i >= pos; I--)
            {
                pArray[i + 1] = pArray[I];
            }
    
            pArray[pos] = val;
    
            mSize++;
        }
    
        // 获取指定位置的值
        int &Get(int pos)
        {
            if (pos >= 0 && pos <= mSize - 1)
            {
                return pArray[pos];
            }
        }
    
        // 在指定位置修改值
        void Set(int pos, int val)
        {
            if (pos < 0 || pos > mSize - 1)
            {
                return;
            }
    
            pArray[pos] = val;
        }
    
    public:
        MyArray()
        {
            // 无参数构造
            mCapacity = 20;
            mSize = 0;
            pArray = new int[mCapacity];
        }
    
        MyArray(int capacity, int val = 0)
        {
            mCapacity = capacity;
            mSize = capacity;
    
            pArray = new int[mCapacity];
    
            for (int i = 0; i < mSize; I++)
            {
                pArray[i] = val;
            }
        }
    
        MyArray(const MyArray &m)
        {
            mSize = m.mSize;
            mCapacity = m.mCapacity;
            // 申请空间
            pArray = new int[mCapacity];
            // 拷贝数据
            for (int i = 0; i < mSize; I++)
            {
                pArray[i] = m.pArray[I];
            }
        }
        // 重写赋值运算符重载函数
        MyArray &operator=(const MyArray &m)
        {
            // 1. 删除原来空间
            if (this->pArray != NULL)
            {
                delete[] pArray;
                pArray = NULL;
            }
    
            this->mCapacity = m.mCapacity;
            this->mSize = m.mSize;
    
            // 2. 申请堆区空间
            this->pArray = new int[this->mCapacity];
    
            // 3.拷贝数据
            for (int i = 0; i < this->mSize; I++)
            {
                this->pArray[i] = m.pArray[I];
            }
    
            // 4.返回对象本身
            return *this;
        }
        // 数组下标运算符重载
        int &operator[](int pos)
        {
            // 赋值时 mSize加加
            if (this->mSize <= pos){
                this->mSize ++;
            }
            return this->pArray[pos];
        }
    
        ~MyArray()
        {
            if (pArray != NULL)
            {
                delete[] pArray;
                pArray = NULL;
            }
        }
    
    private:
        int mCapacity; // 容量
        int mSize;     // 元素个数
        int *pArray;   // 指向堆区空间,存储数据
    };
    
    void test01()
    {
        MyArray arr;
        for (int i = 0; i < 20; I++)
        {
            arr[i] = i + 10;
        }
    
        for (int i = 0; i < 20; I++)
        {
            cout << arr[i] << " ";
        }
        cout << endl;
    }
    
    void test02()
    {
        MyArray arr;
        for (int i = 0; i < 20; I++)
        {
            arr[i] = i + 10;
        }
    
        MyArray arr2; //无参构造
        arr2 = arr; // 赋值运算
    
        for (int i = 0; i < 20; I++)
        {
            cout << arr2[i] << " ";
        }
        cout << endl;
    
    }
    
    

    5. 指针运算符(*、->)重载

    class Person{
    public:
        Person(int param){
            this->mParam = param;
        }
        void PrintPerson(){
            cout << "Param:" << mParam << endl;
        }
    private:
        int mParam;
    };
    
    class SmartPointer{
    public:
        SmartPointer(Person* person){
            this->pPerson = person;
        }
        //重载指针的->、*操作符
        Person* operator->(){
            return pPerson;
        }
        Person& operator*(){
            return *pPerson;
        }
        ~SmartPointer(){
            if (pPerson != NULL){
                delete pPerson;
            }
        }
    public:
        Person* pPerson;
    };
    
    void test01(){
        
        //Person* person = new Person(100);
        //如果忘记释放,那么就会造成内存泄漏
    
        SmartPointer pointer(new Person(100));
        pointer->PrintPerson();
    }
    
    // 智能指针类是管理另一个类的对象的释放
    
    class Maker
    {
    public:
        Maker()
        {
            cout << "Maker 无参构造" << endl;
        }
        void printMaker()
        {
            cout << "Hello Maker" << endl;
        }
        ~Maker()
        {
            cout << "Maker 析构函数" << endl;
        }
    };
    
    class SmartPoint
    {
    private:
        Maker *pMaker;
    public:
        // ->指针运算符重载
        Maker* operator->() {
            return this->pMaker;
        }
        // *星花运算符重载
        Maker& operator*() {
            return *(this->pMaker);
        }
    public:
        SmartPoint(Maker *m)
        {
            cout << "SmartPoint 有参构造函数" << endl;
            pMaker = m;
        };
        ~SmartPoint()
        {
            cout << "SmartPoint 析构函数" << endl;
            if (this->pMaker != NULL)
            {
                delete this->pMaker;
                this->pMaker = NULL;
            }
        };
    };
    
    void test01()
    {
        Maker *p = new Maker;
        SmartPoint sm(p); // 栈区,test01()函数执行完后,会调用SmartPoint的析构函数
        // 当test01()函数结束时,会调用SmartPoint的析构函数,在这个析构函数中delete了Maker的对象,就会调用Maker的析构函数
    
        // (sm->)->printMaker() 编译器优化了
        // sm-> 类似于 pMaker->
        sm->printMaker();
    
        (*sm).printMaker();
    }
    

    6. 函数调用符号() 重载(仿函数)

    如果一个类重载了函数调用符号,那么这个类实例化出来的对象也叫仿函数
    仿函数的作用: 1. 方便代码维护 2.方便有权限的调用函数 3. 作为算法的策略

    // 重载函数调用符号
    // 如果一个类重载了函数调用符号,那么这个类实例化出来的对象也叫仿函数
    // 仿函数的作用: 1. 方便代码维护 2.方便有权限的调用函数 3. 作为算法的策略(后讲)
    class Maker
    {
    public:
        string name;
    
    public:
        // 第一个括号是表示我们要重载函数调用符号,第二个符号表示这是个函数
        void operator()()
        {
            cout << "Hello Maker" << endl;
        }
        void operator()(int val1,int val2){
            cout << val1 + val2 << endl;
        }
    
        void printMaker()
        {
            cout << name + "你好漂亮" << endl;
        }
    
    public:
        Maker()
        {
            cout << "无参构造函数" << endl;
            name = "Emily";
        }
    };
    
    void test01()
    {
        Maker m; // 无参构造 m是对象
        m(); // 看起来像函数,其实m是对象 void operator()()
        m(10,20); // 调用的是函数调用符号重载函数 void operator()(int val1,int val2)
        m.printMaker();
    }
    
    

    7. bool 和 ! 运算符重载

    class Maker
    {
    private:
        int a;
    
    public:
        void SetA(int a)
        {
            this->a = a;
        }
        // 重载bool运算符符
        // 无返回值 无void
        operator bool()
        {
            if (a > 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        
        // 重载!运算符
        bool operator!()
        {
            if (a > 0)
            {
                return false;
            }
            else
            {
                return true;
            }
        }
        // 重载类型(int)运算符
        // 无返回值
        operator int() {
            return 10;
        }
    
    public:
        Maker()
        {
            a = 0;
        };
        ~Maker(){
    
        };
    };
    
    void test01()
    {
        Maker m;
        m.SetA(10);
        if (m)
        {
            cout << "真" << endl;
        }
        else
        {
            cout << "假" << endl;
        }
    
        if (!m)
        {
            cout << "真" << endl;
        }
        else
        {
            cout << "假" << endl;
        }
    
        int b = (int)m;
        cout << b << endl;
    }
    

    8. 运算符和结合性

    image.png image.png image.png image.png

    9. 强化训练-字符串的封装

    MyString.h

    #pragma once
    #include <iostream>
    using namespace std;
    
    class MyString
    {
        friend ostream &operator<<(ostream &os, MyString &str);
        friend istream &operator>>(istream &is, MyString &str);
    
    public:
        MyString();
        MyString(int n, char c = 'a'); // 用户可以设定初始化字符串,n个c组成的字符串
        MyString(const MyString &str);
        MyString &operator=(const MyString &str);
        MyString operator+(const MyString &str);
        MyString operator+(const char *s);
        MyString &operator+=(const MyString &str);
        MyString &operator+=(const char *s);
        char &operator[](int index);
        int Size();
        ~MyString();
    
    private:
        char *pStr; // 指向堆区空间
        int mSize;
    };
    ostream &operator<<(ostream &os, MyString &str);
    istream &operator>>(istream &is, MyString &str);
    
    

    MyString.cpp

    #include "MyString.h"
    
    MyString::MyString()
    {
        cout << "无参构造函数" << endl;
        this->pStr = new char[1];
        this->pStr[0] = '\0';
        this->mSize = 0;
    }
    MyString::MyString(int n, char c)
    {
        cout << "有参构造函数" << endl;
        this->pStr = new char[n + 1];
        for (int i = 0; i < n; i++)
        {
            this->pStr[i] = c;
        }
        // 结束字符'\0'
        // 防止被烫着
        this->pStr[n] = '\0';
    
        this->mSize = n;
    }
    MyString::MyString(const MyString &str)
    {
        cout << "拷贝构造函数" << endl;
        this->pStr = new char[strlen(str.pStr) + 1];
        strcpy(this->pStr, str.pStr);
        this->mSize = str.mSize;
    }
    MyString &MyString::operator=(const MyString &str)
    {
        cout << "运算符重载 =" << endl;
        // 1.释放原来空间
        if (this->pStr != NULL)
        {
            delete[] this->pStr;
            this->pStr = NULL;
        }
    
        // 2.申请空间
        this->pStr = new char[strlen(str.pStr) + 1];
        // 3.拷贝数据
        strcpy(this->pStr, str.pStr);
    
        this->mSize = str.mSize;
    
        // 返回对象本身
        return *this;
    }
    MyString MyString::operator+(const MyString &str)
    {
        cout << "运算符重载 + MyString" << endl;
        // MyString s3=s1+s2
        // 获取s3要开辟的空间大小
        int newlen = this->mSize + str.mSize + 1;
    
        // 1.定义一个临时变量
        MyString tmp;
    
        // 2.释放原来空间
        if (tmp.pStr != NULL)
        {
            delete[] tmp.pStr;
            tmp.pStr = NULL;
        }
        // 3.申请新的空间
        tmp.pStr = new char[newlen];
        // 清除下空间
        memset(tmp.pStr, 0, newlen);
    
        tmp.mSize = this->mSize + str.mSize;
    
        // 4.追加字符到空间中
        strcat(tmp.pStr, this->pStr);
        strcat(tmp.pStr, str.pStr);
    
        // 5. 返回临时变量
        return tmp;
    }
    MyString MyString::operator+(const char *s)
    {
        cout << "运算符重载 + Char" << endl;
        int newlen = this->mSize + strlen(s);
        // 开辟空间
        char *newspace = new char[newlen + 1];
        memset(newspace, 0, newlen + 1);
    
        // 追加数据到空间
        strcat(newspace, this->pStr);
        strcat(newspace, s);
    
        MyString tmp;
        if (tmp.pStr != NULL)
        {
            delete[] tmp.pStr;
            tmp.pStr = NULL;
        }
    
        tmp.pStr = newspace;
    
        tmp.mSize = newlen;
        
        return tmp;
    
    
    }
    MyString &MyString::operator+=(const MyString &str)
    {
        cout << "运算符重载 += MyString" << endl;
        int newlen = this->mSize + strlen(str.pStr);
    
        // 1.开辟空间
        char * newspace = new char[newlen + 1];
        memset(newspace,0, newlen+1);
        // 2.追加数据
        strcat(newspace, this->pStr);
        strcat(newspace, str.pStr);
    
        // 3.释放原来空间
        if (this->pStr != NULL)
        {
            delete[] this->pStr;
            this->pStr = NULL;
        }
        // 4.指向newspace
        this->pStr = newspace;
    
        this->mSize = newlen;
    
        return *this;
    
        
    
    }
    MyString &MyString::operator+=(const char *s)
    {
        cout << "运算符重载 += Char" << endl;
        int newlen = this->mSize + strlen(s);
    
        char *newspace = new char[newlen + 1];
        memset(newspace, 0, newlen+1);
    
        strcat(newspace, this->pStr);
        strcat(newspace, s);
    
        if (this->pStr != NULL)
        {
            delete[] this->pStr;
            this->pStr = NULL;
        }
    
        this->pStr = newspace;
        this->mSize = newlen;
    
        return *this;
    
    }
    char &MyString::operator[](int index)
    {
        return this->pStr[index];
    }
    int MyString::Size()
    {
        return mSize;
    }
    MyString::~MyString()
    {
        if (this->pStr != NULL)
        {
            delete[] this->pStr;
            this->pStr = NULL;
        }
    }
    
    ostream &operator<<(ostream &os, MyString &str)
    {
        os << str.pStr;
        return os;
    }
    istream &operator>>(istream &is, MyString &str)
    {
        // 1. 定义临时空间
        char tmp[1024] = {0};
        // 2.获取用户输入的信息
        is>>tmp;
        // 3.释放原来空间
        if (str.pStr != NULL)
        {
            delete[] str.pStr;
            str.pStr = NULL;
        }
    
        // 4.申请新的空间
        str.pStr = new char[strlen(tmp) + 1];
        memset(str.pStr,0, strlen(tmp)+1);
    
        // 5.拷贝用户输入的信息
        strcpy(str.pStr,tmp);
        str.mSize = strlen(tmp);
        return is;
    
    }
    

    相关文章

      网友评论

          本文标题:C++ 运算符重载(二)(11)

          本文链接:https://www.haomeiwen.com/subject/cgsvvrtx.html