六、运算符重载

一、加号运算符重载(+)

1.1 成员函数实现加号运算符重载

/*
    Person operator+ (Person &p);
*/
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;

class Person
{
public:
    Person() {}
    Person(int a, int b) :A(a), B(b)
    {}

    // + 运算符重载, 成员函数
    Person operator+ (Person &p)  // 二元
    {
        Person tmp; // 会走默认构造,所以需要默认构造
        tmp.A = this->A + p.A;
        tmp.B = this->B + p.B;
        return tmp;
    }

    int A;
    int B;
};

void test01()
{
    Person p1(10, 20);
    Person p2(20, 30);
    Person p3 = p1 + p2;  // 本质上是 p1.operate(p2), 但是已经封装成了 p1+p2
    cout << "p3.A = " << p3.A << endl; // 30
    cout << "p3.B = " << p3.B << endl; // 50
}

int main()
{
    test01();
    return EXIT_SUCCESS;
}

1.2 全局函数实现加号运算符重载

/* 
    Person operator+ (Person &p1, Person &p2);
    Person operator+ (Person &p1, int val);
*/
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;

class Person
{
public:
    Person() {}
    Person(int a, int b) :A(a), B(b)
    {}

    int A;
    int B;
};

// 利用全局函数进行 + 运算符重载
Person operator+ (Person &p1, Person &p2) // 二元
{
    Person tmp;  // 会走默认构造,所以需要默认构造
    tmp.A = p1.A + p2.A;
    tmp.B = p1.B + p2.B;
    return tmp;
}

// 加号运算符重载可以发生函数重载
Person operator+ (Person &p1, int val)
{
    Person tmp;  // 会走默认构造,所以需要默认构造
    tmp.A = p1.A + val;
    tmp.B = p1.B + val;
    return tmp;
}

void test01()
{
    Person p1(10, 20);
    Person p2(20, 30);
    Person p3 = p1 + p2;
    Person p4 = p1 + 30;
    cout << "p3.A = " << p3.A << endl; // 30
    cout << "p3.B = " << p3.B << endl; // 50
    cout << "p4.A = " << p4.A << endl; // 40
    cout << "p4.B = " << p4.B << endl; // 50
}

int main()
{
    test01();
    return EXIT_SUCCESS;
}

 

二、左移运算符重载(<<)

 

/*
    ostream& operator<<(ostream &cout, Person &p1);
    如果重载的时候,需要访问私有的成员属性,需要将全局函数设置为友元函数
*/
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;

class Person
{
    friend ostream& operator<<(ostream &cout, Person &p1);
public:
    Person() {}
    Person(int a, int b) 
    {
        this->A = a;
        this->B = b;
    }

    // 重载左移运算符
    // 如果这样写,调用的时候为 p1.operate()...,也就是 p1<<不符合调用的时候 cout <<... 规则,
    // 所以重载左移运算符不能写在成员函数中
    //void operator<<()  
    //{
    //}
private:
    int A;
    int B;
};

// 全局函数进行 左移运算符
// 根据 加号运算符重载 p1 + p2 , + 左右两边为两个参数, 
// 所以 cout << p1, << 运算符左右分别为 cout, p1
// 所以第一个参数 cout, 第二个参数 p1
// cout 的类型是  ostream
ostream& operator<<(ostream &cout, Person &p1)
{
    cout << "A = " << p1.A << "  B = " << p1.B; // A,B都是public没问题,当A,B都是privite的时候,需要将这个函数加入友元函数
    return cout; // 直接返回 cout, 这样 cout<<p1的返回值就是cout类型,再继续 << endl就不会有问题了

}

void test01()
{
    Person p1(10, 20);
    
    cout << p1 << endl;
}

int main()
{
    test01();
    return EXIT_SUCCESS;
}

 

三、自增自减运算符重载(++--)

 

/*
    前置递增返回引用,后置递增返回值
    MyInteger& operator++();  前置++
    MyInteger operator++(int); 后置++
*/

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;

class MyInteger
{
    friend ostream& operator<<(ostream&cout, MyInteger  myInt);
public:
    MyInteger()
    {
        this->num = 0;
    }
    // 前置++重载
    /*
        如果没有&, 就是MyInteger operator++(); 那么 cout<< ++(++myInt) << endl;的输出结果是2
        但是 cout << myInt<< endl;的输出结果是 1, 因为返回的不是引用,第一次做完运算以后是一个临         时数据,第二次++操作的不是 myInt本体了,所以输出结果是 1
    */
    MyInteger& operator++()
    {
        this->num++;
        return *this;
    }
    // 后置++重载, 和前置++区别就是加了一个 int 占位参数的用途
    MyInteger operator++(int)
    {
        // 先保存目前的数据
        MyInteger tmp = *this;
        this->num++;
        // 返回原始数据
        return tmp;
    }
private:
    int num;
};

ostream& operator<<(ostream&cout, MyInteger myInt)
{
    cout << myInt.num ;
    return cout;
}

void test()
{
    MyInteger myInt;
    cout << ++myInt << endl;  // 1 前置++, 直接这样写的话,myInt是MyInteger类型,cout<<输出不识别,所以 需要左移运算符重载
    cout << myInt++ << endl;  // 1 后置++
    cout << myInt << endl;    // 2
}

int main()
{
    test();
    return EXIT_SUCCESS;
}

 

四、指针运算符重载(*、->

/*
    如果 new 出来的对象,需要自己去 delete,有了智能指针,就能帮我们托管这个对象,对象的释放就不需要我们自己管了。为了让智能指针能够和普通的指针一样使用,需要重载 -> 和 * 两个指针操作
    
    Person * operator->(); 重载 ->
    Person& operator*();   重载 *
*/
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;

class Person
{
public:
    Person(int age)
    {
        this->Age = age;
    }
    ~Person()
    {
        cout << "Person析构" << endl;
    }
    void showAge()
    {
        cout << "年龄为 " << this->Age << endl;
    }
    int Age;
};

// 智能指针
// 用来托管自定义类型的对象,让对象进行自动的释放
class smartPointer
{
public:
    smartPointer(Person * person)
    {
        this->person = person;
    }
    ~smartPointer()
    {
        cout << "智能指针析构" << endl;
        if (this->person != NULL)
        {
            delete this->person;
            this->person = NULL;
        }
    }
    // 重载 -> , 让智能指针对象能像Person对象一样使用 showAge()方法
    Person * operator->()
    {
        return this->person;
    }
    // 重载 *
    Person& operator*()
    {
        return *this->person;
    }

private:
    Person * person;
};

void test01()
{
    //Person p1(10);  // 开辟在栈上,自动析构
    //Person *p1 = new Person(10);  // 开辟在堆上
    //p1->showAge();   可以直接调用 showAge()方法
    //delete p1; // 需要自动释放

    smartPointer sp(new Person(10));  // sp开辟到了栈上,会自动释放
    sp->showAge();//  因为sp不存在在showAge方法, 所以需要重载 -> ,但是根据重载之后 sp->的返回值是指针, 所以实际上应该是 sp->->showAge(); 但是编译器自己帮我们优化了
    // sp是一个指针, 所以希望能够 (*sp).showAge(), 所以需要重载 *运算符
    (*sp).showAge();

}

int main()
{
    test01();
    return EXIT_SUCCESS;
}

 

 

五、赋值运算符重载(=)

 

/*
    系统秒人给类提供 赋值运算符写法,是简单的值拷贝, 会出现导致如果类中有指向堆区的指针, 就可能出现深浅拷贝的问题, 所以需要重载 = 运算符, 因为存在链式赋值编程, 所以需要返回 *this;
    Person2& operator=(const Person2 &p);
*/

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;

class Person
{
public:
    Person(int a)
    {
        this->A = a;
    }
    int A;
};


class Person2
{
public:
    Person2(char *name)
    {
        this->pName = new char[strlen(name) + 1];
        strcpy(this->pName, name);
    }
    ~Person2()
    {
    
        if (this->pName == NULL)
        {
            delete[] this->pName;
            this->pName = NULL;
        }
    }

    // 重载 = 运算符
    Person2& operator=(const Person2 &p)
    {
        // 先判断原来已经堆区有内容,先释放
        if (this->pName != NULL)
        {
            delete[] this->pName;
            this->pName = NULL;
        }
        this->pName = new char[strlen(p.pName) + 1];
        strcpy(this->pName, p.pName);

        // 如果连等的话, 需要返回本体
        return *this;
    }

    char *pName;
};


void test01()
{
    Person p1(10);
    Person p2(0);
    p2 = p1;
    // 一个类在创建的时候,默认会我们创建 默认构造,拷贝构造, 析构函数 还有一个 =赋值运算符(operator=)
    // 会进行简单的值传递, 所以会将 p1里面的值赋值给 p2
    cout << "p2.A = " << p2.A << endl;  // p2.A = 10 
}


void test02()
{
    Person2 p3("wang");
    Person2 p4("yong");
    p4 = p3;
    cout << "p2.Name = " << p4.pName << endl;  // wang
    // p4 = p3之后会进行值拷贝,将p3内的地址传递给p4,当p3析构以后,释放完以后, p4也需要释放,但是释放的空间已经为NULL
    // 所以就会报错,出现了深浅拷贝的问题, 所以需要重载等号运算符
    Person2 p5("123");

    p5 = p4 = p3;  // 存在连等, 所以需要返回 本体
    cout << "p5.Name = " << p4.pName << endl;  // wang

}


int main()
{
    test01();
    test02();
    return EXIT_SUCCESS;
}

 

六、数组运算符重载([ ])

https://www.cnblogs.com/wangyong123/articles/16005731.html#_label2

 

七、关系运算符重载(==、!=)

 

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<string>
using namespace std;

// == 运算符重载

class Person
{
public:
    Person(string name, int age)
    {
        this->Name = name;
        this->Age = age;
    }
    bool operator==(Person &p)
    {
        if (this->Age == p.Age && this->Name == p.Name)
        {
            return true;
        }
        return false;
    }
    bool operator!=(Person &p)
    {
        if (this->Age == p.Age && this->Name == p.Name)
        {
            return false;
        }
        return true;
    }

    string Name;
    int Age;
};

void test()
{
    Person p1("wang", 27);
    Person p2("yong", 27);
    if (p1 == p2)
    {
        cout << "p1与p2相等" << endl;
    }
    else
    {
        cout << "p1和p2不相等" << endl;
    }
    if (p1 != p2)
    {
        cout << "p1与p2不相等" << endl;
    }
    else
    {
        cout << "p1和p2相等" << endl;
    }
}

int main()
{
    test();
    return EXIT_SUCCESS;
}

 

八、函数调用运算符重载(())

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<string>
using namespace std;

// == 运算符重载

class MyPrint
{
public:
    void operator()(string text)
    {
        cout << text << endl;
    }
};
class MyAdd
{
public:
    int operator()(int a, int b)
    {
        return a + b;
    }
};

void test()
{
    MyPrint myprint;
    myprint("Hello World");  // 仿函数
    MyAdd myadd;
    cout << myadd(10, 20) << endl;
    cout << MyAdd()(20, 30) << endl;  // 匿名对象
}

int main()
{
    test();
    return EXIT_SUCCESS;
}

 

九、逻辑运算符一般不重载(&&、||)

不要重载 &&,|| 运算符, 因为无法实现短路规则

 

十、符号重载总结

=, [], (), -> 操作运算符只能通过成员函数进行重载

<<, >>只能通过区研究院函数配合友元函数进行重载

不要重载 && 和 ||, 因为无法实现短路规则

运算符建议使用
所有的一元运算符 成员
=,(), ->, * 必须是成员
+=,-=,/=,^=,&=,!=,%=,>>=,<<= 成员
其他二元运算符 非成员

 

 十一、运算符重载练习:字符串的封装

11.1 MySting.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<string>
using namespace std;

class MyString
{
    friend ostream& operator<<(ostream &cout, MyString & str);
    friend istream& operator>>(istream &cin, MyString &str);
public:
    MyString(char * str);
    MyString(const MyString & str);
    ~MyString();

    // = 运算符重载
    MyString& operator=(const char *str);
    MyString& operator=(const MyString &str);
    
    // [] 运算符重载
    char& operator[](int index);

    // + 运算符重载
    MyString operator+(const char * str);
    MyString operator+(const MyString & str);

    // == 运算符重载
    bool operator==(const char *str);
    bool operator==(const MyString &str);

    

private:
    char *pString;  //执行堆区的指针
    int Size;       // 字符串大小
};

 

11.2 MySting.cpp

#include "MyString.h"

MyString::MyString(char * str)
{
    cout << "有参构造调用" << endl;
    this->pString = new char[strlen(str) + 1];
    strcpy(this->pString, str);
    this->Size = strlen(str);
}


MyString::MyString(const MyString & str)
{
    this->pString = new char[strlen(str.pString) + 1];
    this->Size = str.Size;
    strcpy(this->pString, str.pString);
}


MyString::~MyString()
{
    if (this->pString == NULL)
    {
        delete[] this->pString;
        this->pString = NULL;
    }
}

// 左移运算符重载
ostream& operator<<(ostream &cout, MyString & str)
{
    cout << str.pString;
    return cout;
}

// 右移运算符重载
istream& operator>>(istream &cin, MyString &str)
{
    // 先把原有的内容清空
    if (str.pString != NULL)
    {
        delete [] str.pString;
        str.pString = NULL;
    }
    // 让用户输入内容
    char buff[1024];
    cin >> buff;
    // 把用户输入的字符串赋值给 pString
    str.pString = new char[strlen(buff) + 1];
    strcpy(str.pString, buff);
    str.Size = strlen(buff);
    return cin;
}

// =运算符重载
MyString& MyString::operator=(const char *str)
{
    if (this->pString != NULL)
    {
        delete[] this->pString;
        this->pString = NULL;
    }
    this->pString = new char[strlen(str) + 1];
    strcpy(this->pString, str);
    return *this;
}

MyString& MyString::operator = (const MyString &str)
{
    if (this->pString != NULL)
    {
        delete[] this->pString;
        this->pString = NULL;
    }
    this->pString = new char[strlen(str.pString) + 1];
    strcpy(this->pString, str.pString);
    return *this;
}

char& MyString::operator[](int index)
{
    return this->pString[index];
}


MyString MyString::operator + (const char * str)
{
    // 计算返回的字符串开辟的大小
    int newSize = this->Size + strlen(str) + 1;
    char *tmp = new char[newSize];
    memset(tmp, 0, newSize);
    // 字符串拼接
    strcat(tmp,this->pString);
    strcat(tmp, str);

    MyString newStr(tmp);
    delete[] tmp;
    return newStr;
}
MyString MyString::operator + (const MyString & str)
{
    // 计算返回的字符串开辟的大小
    int newSize = this->Size + strlen(str.pString) + 1;
    char *tmp = new char[newSize];
    memset(tmp, 0, newSize);
    // 字符串拼接
    strcat(tmp, this->pString);
    strcat(tmp, str.pString);

    MyString newStr(tmp);
    delete[] tmp;
    return newStr;
}

bool MyString::operator == (const char *str)
{
    if (strcpy(this->pString, str) == 0 && this->Size == strlen(str))
    {
        return true;
    }
    return false;
}
bool MyString::operator == (const MyString &str)
{
    if (strcpy(this->pString, str.pString) == 0 && this->Size == strlen(str.pString))
    {
        return true;
    }
    return false;
}

 

11.3 main.cpp

#include "MyString.h"


void test()
{
    MyString str = "abc";
    // 重载左移运算符
    cout << str << endl;
    cout << "请输入 str 新的内容" << endl;
    // 右移运算符重载
    cin >> str;
    cout << "str 新的内容是 " << str << endl;

    MyString str2(str);
    MyString str3 = "";
    // = 运算符重载
    str3 = str2;
    cout << "str3 = " << str3 << endl;
    str3 = "aaa";
    cout << "str3 = " << str3 << endl;
    // [] 运算符重载
    cout << "str3 第一个位置为 " << str3[0] << endl;
    str3[0] = 'z';
    cout << "str3 第一个位置为 " << str3[0] << endl;

    MyString str4 = "";
    // + 运算符重载
    str4 = str2 + str3;
    cout << "str4 = " << str4 << endl;

    // ==运算符重载
    if (str3 == str4)
    {
        cout << "str3与str4相等" << endl;
    }
    else
    {
        cout << "str3与str4不相等" << endl;
    }

}

int main()
{
    test();
    return EXIT_SUCCESS;
}

 

 

 

 

posted on 2022-03-14 20:36  软饭攻城狮  阅读(14)  评论(0编辑  收藏  举报

导航