C++运算符重载

C++运算符重载

对于内置数据类型而言可以进行正常的运算符使用,而对于自定义的数据类型则无法与之匹配。

对于这个问题我们一般使用函数来解决,而编译器为我们提供了一个标准的命名方式可以简化调用方式,实现自定义数据类型的运算符使用,我们称其为运算符重载

关键字:operator+运算符

 


重载方式

成员函数重载(在类内)

全局函数重载(在全局区)

 


 

加号运算符重载

 

 

参考代码:

#include <iostream>//关键词 operator
using namespace std;
​
//运算符重载的概念:对已有的运算符重新定义,赋予其另一种功能,以适应不同的数据类型
​
//加号运算符重载
class Person
{
public:
​
    //1、成员函数重载+号
    /*Person operator+(Person &P)
    {
        Person temp;
        temp.m_A = this->m_A + P.m_A;
        temp.m_B = this->m_B + P.m_B;
        return temp;
    }*/
​
    int m_A;
    int m_B;
};
​
//2、全局函数重载+号
Person operator+(Person &P1, Person &P2)
{
    Person temp;
    temp.m_A = P1.m_A + P2.m_A;
    temp.m_B = P1.m_B + P2.m_B;
    return temp;
}
​
//“函数重载”的版本(前面学过的函数重载)
Person operator+(Person &P1, int num)   //函数名可以复用 只是形参:类型、个数、顺序组合的有所不同
{
    Person temp;
    temp.m_A = P1.m_A + num;
    temp.m_B = P1.m_B + num;
    return temp;
}
​
void test01()
{
    Person P1;
    P1.m_A = 10;
    P1.m_B = 10;
​
    Person P2;
    P2.m_A = 10;
    P2.m_B = 10;
​
    //简化调用:
    Person P3 = P1 + P2;
​
    //成员函数重载本质调用:
    //Person P3 = P1.operator + (P2);
​
    //全局函数重载的本质调用:
    //Person P3 = operator+(P1, P2);
​
    //运算符重载,也可以发生函数重载
    Person P4 = P1 + 10;            //Person + int
​
    cout << "P3.m_A=" << P3.m_A << endl;
    cout << "P3.m_B=" << P3.m_B << endl;
​
    cout << "P4.m_A=" << P4.m_A << endl;
    cout << "P4.m_B=" << P4.m_B << endl;
}
​
​
int main()
{
​
    test01();
​
    system("pause");
    return 0;
}

 

 

 


 

左移运算符重载

 

参考代码:

#include <iostream>
using namespace std;
​
//可以输出自定义数据类型
class Person
{
friend ostream& operator<<(ostream &cout, Person &P);   //全局函数做友元
​
public: //在定义一个默认构造函数初始化
    Person()
    {
        m_A = 10;
        m_B = 10;
    }
​
​
//更改一下public:
private:    //一般成员属性用私有权限(使用友元!)
​
    //利用成员函数来重载一个 << 运算符 
    //一开始使用:void operator<<(Person &P)时,调用时 P.opertor<<(P)显然不符合
    //现在:简化版本 P << cout; 显然先后次序发生了变化(看不懂就参考一下 加号的 成员函数重载简化)
    //不会利用成员函数重载 << 运算符,因为无法实现 cout在左侧
    /*void operator<<(cout)
    {
​
    }*/
​
    int m_A;
    int m_B;
};
​
​
//这个重载函数是没有返回值的
//只能利用全局运算符重载左移运算符  cout的数据类型可以通过查看定义来看
ostream& operator<<(ostream &cout, Person &P)   //本质 operator<<(cout,P) 简化 cout << P
{
    cout << "m_A = " << P.m_A << "m_B = " << P.m_B;
    return cout;    //引用做函数返回值 函数调用可以作为左值 此处是为了进行链式追加
​
    //最后注意:引用本身就是取别名,所以这里使用out也可以
}
​
void test01()
{
    Person P;
​
    //为了实现直接输出对象,而重载左运算符
    cout << P << endl << "Hello world!" << endl;    //想要链式追加?
}
​
​
int main()
{
​
    test01();
​
    system("pause");
    return 0;
}

 

 


 

递增运算符重载

 

#include <iostream>
using namespace std;
​
//作用:通过重载递增运算符,实现自己的整形数据
​
//重载递增运算符
​
//自定义整型
class MyInteger
{
    //全局函数做友元 使其可以访问类中的私有变量
    friend ostream& operator << (ostream &cout, MyInteger myint);
​
public:
    MyInteger()
    {
        m_Num = 0;
    }
​
    //重载前置++运算符
    MyInteger& operator++() //返回值是递增是为了保证 在连续自增时 是对一个数据进行递增
    {
        //先进行++运算
        m_Num++;
​
        //再将自身做返回
        return *this;
    }
​
    //同一个作用域下 函数名一样 但是参数。。。 (返回值与函数重载无关)
​
    //重载后置++运算符
    //这里只能够用 int 不能用其它数据类型
    MyInteger operator++(int)   //加上一个 占位参数,可以用于区分前置和后置递增
    {
        //先 返回结果(但是直接return函数就会运行结束)
        //所以:先记录一下当时的结果
        
        MyInteger temp = *this;
​
        //再 进行++运算
​
        m_Num++;
        
        //最后将记录结果做返回
​
        return temp;    //!!!注意后置返回的是一个值
        //原因:我们返回的是一个局部变量,在函数运行结束后会被释放,后续再进行访问是非法操作
    }
​
​
​
private:
    int m_Num;
};
​
//重载 << 算符
ostream& operator << (ostream &cout, MyInteger myint)
{
    cout << myint.m_Num;
​
    return cout;
}
​
//前置递增
void test01()
{
    MyInteger myint;    //myint是创建的一个对象
​
    cout << ++(++myint) << endl;    //此处需要实现myint的 左移位运算 与 自增运算
    cout << myint << endl;          //显然通过此行输出我们可以看出 
    //如果返回类型不是一个引用 那么就不是在同一个数据上进行这两次自增操作
}
​
//后置递增
void test02()
{
    MyInteger myint;
​
    cout << myint++ << endl;
​
    cout << myint << endl;
}
​
int main()
{
    //前置
    //test01();
​
    //后置
    test02();
​
​
    //在内置的此类操作中 两次前置递增 都是在同一个数据上进行
    /*int a = 0;
​
    cout << ++(++a) << endl;
    cout << a << endl;*/
​
    system("pause");
    return 0;
}

 

 


 

递减运算符重载

 

参考代码:

#include <iostream>
using namespace std;
​
class MyInteger
{
    friend ostream& operator<<(ostream &cout, MyInteger myint); //全局函数做友元
public:
​
    MyInteger()     //自定义默认构造函数,初始化成员变量数值
    {
        m_Num = 0;
    }
​
    //前置递减
    MyInteger& operator--()//此处返回类的引用 是为了进行链式编程 
    {
        m_Num--;
​
        return *this;
    }
​
    //后置递减
    MyInteger operator--(int)   //占位形参用于区分 前置与后置
    {
        MyInteger temp = *this; 
​
        m_Num--;
​
        return temp;
    }
​
private:
    int m_Num;
};
​
//重载<<运算符
ostream& operator<<(ostream &cout,MyInteger myint )//返回值为cout的引用使其可以作为左值
{
    cout << myint.m_Num;    //本身传入对象无法接收 这里就相当于构造了一个函数来传入对象中的可接受值
​
    return cout;
}
​
​
​
//前置递减
void test01()
{
    MyInteger myint;
​
    cout << --(--myint) << endl;    //测试是否能够连续递增(链式编程追加)
​
    cout << myint << endl;
}
​
//后置递减
void test02()
{
    MyInteger myint;
​
    cout << myint-- << endl;
​
    cout << myint << endl;
}
​
int main()
{
​
    //test01();
​
    test02();
​
    system("pause");
    return 0;
}

 

 


 

赋值运算符重载

 

参考代码:

#include <iostream>
using namespace std;
​
//C++编译器至少给一个类添加4个函数
//1、默认构造函数(无参,函数体为空)
//2、默认析构函数(无参,函数体为空)
//3、默认拷贝函数,对属性进行值拷贝
​
//4、赋值运算符operator=,对属性进行值拷贝(也会和浅拷贝一样,引起堆区内存重复释放)
//即:简单拷贝,会连着将地址值也拷贝到另一个对象里,
//当我们提供的成员属性是堆区的地址时,需要借助析构函数进行内存释放,此时就会引起堆区内存的重复释放
​
​
//赋值运算符重载
class Person
{
public:
​
    Person(int age)
    {
        m_Age = new int(age);   //用关键词 new 创建在了堆区
    }
​
    ~Person()//堆区的内存重复释放
    {
        if (m_Age != NULL)
        {
            delete m_Age;
            m_Age = NULL;
        }
    }
​
    //重载 赋值运算符
    Person& operator=(Person &P)
    {
        //编译器是提供的浅拷贝
        //m_Age = P.m_Age;
​
        //因该先判断是否有属性在堆区,如果有先释放干净,然后再深拷贝
        if (m_Age != NULL)
        {
            delete m_Age;
            m_Age = NULL;
        }
        //深拷贝:
        m_Age = new int(*P.m_Age);
​
        return *this;   //此操作是为了连续赋值
    }
​
    int *m_Age;
};
​
void test01()
{
    Person P1(18);
​
    Person P2(20);
​
    Person P3(30);
​
    P3 = P2 = P1;   //赋值操作
​
    cout << "P1的年龄为:" << *P1.m_Age << endl;
​
    cout << "P2的年龄为:" << *P2.m_Age << endl;
​
    cout << "P3的年龄为:" << *P3.m_Age << endl;
​
}
​
int main()
{
    test01();
​
​
    //对于内置数据类型支持连续赋值
    /*int a = 10;
    int b = 20;
    int c = 30;
​
    c = b = a;
​
    cout << "a=" << a << endl;
    cout << "b=" << b << endl;
    cout << "c=" << c << endl;*/
​
    system("pause");
    return 0;
}

 


 

关系运算符重载

 

参考代码:

#include <iostream>
#include <string>
using namespace std;
​
//重载关系运算符
​
class Person
{
public:
    Person(string name, int age)
    {
        m_Name = name;
        m_Age = age;
    }
​
    //重载 == 号
    bool operator==(Person &P)
    {
        if (P.m_Age == this->m_Age&&P.m_Name == this->m_Name)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
​
    //重载 != 号
    bool operator!=(Person &P)
    {
        if (P.m_Age != this->m_Age || P.m_Name != this->m_Name)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
​
    string m_Name;
    int m_Age;
};
​
//测试 == 的重载
void test01()
{
    Person P1("张三", 18);
​
    Person P2("张三", 18);
​
    if (P1 == P2)
    {
        cout << "P1与P2是相等的" << endl;
    }
    else
    {
        cout << "P1与P2是不相等的" << endl;
    }
}
​
//测试 != 的重载
void test02()
{
    Person P1("张三", 18);
​
    Person P2("张三", 18);
​
    if (P1 != P2)
    {
        cout << "P1与P2不是相等的" << endl;
    }
    else
    {
        cout << "P1与P2是相等的" << endl;
    }
}
​
int main()
{
​
    test01();
​
    test02();
​
    system("pause");
    return 0;
}

 

 


 

函数调用运算符重载

 

参考代码:

#include <iostream>
#include <string>
using namespace std;
​
//函数调用运算符 () 重载
//由于重载后使用的方式非常像函数的调用,因此成为仿函数
//仿函数没有固定的写法,非常灵活   (在后续的STL里面涉及的多)
​
//打印输出类
class MyPrint
{
public:
​
    //重载函数调用运算符 //成员函数重载
    void operator()(string test)
    {
        cout << test << endl;
    }
​
​
};
​
void MyPrint02(string test)
{
    cout << test << endl;
}
​
void test01()
{
    MyPrint myPrint;
    myPrint("hello world");     //重载过后一个对象进行调用  由于使用起来非常类似一个函数调用,因此称为仿函数
​
    MyPrint02("hello world");   //一个函数调用
}
​
//仿函数非常灵活,没有固定的写法
​
//加法类
class MyAdd
{
public:
    
    int operator()(int num1,int num2)   //比较两个仿函数的写法 形式不是唯一的(参数个数与返回值等)
    {
        return num1 + num2;
    }
};
​
void test02()
{
    MyAdd myadd;
    int ret = myadd(100, 100);
    cout << "ret = " << ret << endl;
​
    //匿名函数对象 
    //回忆匿名对象 MyAdd() 等价于 本类的对象名
    //因此处重载了()使得这个匿名对象进行了仿函数调用 所以称其为匿名函数对象
    cout << MyAdd()(100, 100) << endl;  //先创建一个对象执行后直接释放(参考构造函数的调用)
​
}
​
int main()
{
    
    //test01();
​
    test02();
​
    system("pause");
    return 0;
}
 
posted @ 2022-06-27 13:31  如此而已~~~  阅读(69)  评论(0)    收藏  举报
//雪花飘落效果