运算符重载概念:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型

1 加号运算符重载

作用:实现两个自定义数据类型相加的运算

  1. class Person {
  2. public:
  3. Person() {};
  4. Person(int a, int b)
  5. {
  6. this->m_A = a;
  7. this->m_B = b;
  8. }
  9. //成员函数实现 + 号运算符重载
  10. Person operator+(const Person& p) {
  11. Person temp;
  12. temp.m_A = this->m_A + p.m_A;
  13. temp.m_B = this->m_B + p.m_B;
  14. return temp;
  15. }
  16. public:
  17. int m_A;
  18. int m_B;
  19. };
  20. //全局函数实现 + 号运算符重载
  21. //Person operator+(const Person& p1, const Person& p2) {
  22. // Person temp(0, 0);
  23. // temp.m_A = p1.m_A + p2.m_A;
  24. // temp.m_B = p1.m_B + p2.m_B;
  25. // return temp;
  26. //}
  27. //运算符重载 可以发生函数重载
  28. Person operator+(const Person& p2, int val)
  29. {
  30. Person temp;
  31. temp.m_A = p2.m_A + val;
  32. temp.m_B = p2.m_B + val;
  33. return temp;
  34. }
  35. void test() {
  36. Person p1(10, 10);
  37. Person p2(20, 20);
  38. //成员函数方式
  39. Person p3 = p2 + p1; //相当于 p2.operaor+(p1)
  40. cout << "mA:" << p3.m_A << " mB:" << p3.m_B << endl;
  41. Person p4 = p3 + 10; //相当于 operator+(p3,10)
  42. cout << "mA:" << p4.m_A << " mB:" << p4.m_B << endl;
  43. }
  44. int main() {
  45. test();
  46. system("pause");
  47. return 0;
  48. }

总结1:对于内置的数据类型的表达式的的运算符是不可能改变的

总结2:不要滥用运算符重载

2 左移运算符重载

作用:可以输出自定义数据类型

  1. class Person {
  2. friend ostream& operator<<(ostream& out, Person& p);
  3. public:
  4. Person(int a, int b)
  5. {
  6. this->m_A = a;
  7. this->m_B = b;
  8. }
  9. //成员函数 实现不了 p << cout 不是我们想要的效果
  10. //void operator<<(Person& p){
  11. //}
  12. private:
  13. int m_A;
  14. int m_B;
  15. };
  16. //全局函数实现左移重载
  17. //ostream对象只能有一个
  18. ostream& operator<<(ostream& out, Person& p) {
  19. out << "a:" << p.m_A << " b:" << p.m_B;
  20. return out;
  21. }
  22. void test() {
  23. Person p1(10, 20);
  24. cout << p1 << "hello world" << endl; //链式编程
  25. }
  26. int main() {
  27. test();
  28. system("pause");
  29. return 0;
  30. }

总结:重载左移运算符配合友元可以实现输出自定义数据类型

3 递增运算符重载

作用: 通过重载递增运算符,实现自己的整型数据

  1. class MyInteger {
  2. friend ostream& operator<<(ostream& out, MyInteger myint);
  3. public:
  4. MyInteger() {
  5. m_Num = 0;
  6. }
  7. //前置++
  8. MyInteger& operator++() {
  9. //先++
  10. m_Num++;
  11. //再返回
  12. return *this;
  13. }
  14. //后置++
  15. MyInteger operator++(int) {
  16. //先返回
  17. MyInteger temp = *this; //记录当前本身的值,然后让本身的值加1,但是返回的是以前的值,达到先返回后++;
  18. m_Num++;
  19. return temp;
  20. }
  21. private:
  22. int m_Num;
  23. };
  24. ostream& operator<<(ostream& out, MyInteger myint) {
  25. out << myint.m_Num;
  26. return out;
  27. }
  28. //前置++ 先++ 再返回
  29. void test01() {
  30. MyInteger myInt;
  31. cout << ++myInt << endl;
  32. cout << myInt << endl;
  33. }
  34. //后置++ 先返回 再++
  35. void test02() {
  36. MyInteger myInt;
  37. cout << myInt++ << endl;
  38. cout << myInt << endl;
  39. }
  40. int main() {
  41. test01();
  42. //test02();
  43. system("pause");
  44. return 0;
  45. }

总结: 前置递增返回引用,后置递增返回值

4 赋值运算符重载

c++编译器至少给一个类添加4个函数

  1. 默认构造函数(无参,函数体为空)
  2. 默认析构函数(无参,函数体为空)
  3. 默认拷贝构造函数,对属性进行值拷贝
  4. 赋值运算符 operator=, 对属性进行值拷贝

如果类中有属性指向堆区,做赋值操作时也会出现深浅拷贝问题

示例:

  1. class Person
  2. {
  3. public:
  4. Person(int age)
  5. {
  6. //将年龄数据开辟到堆区
  7. m_Age = new int(age);
  8. }
  9. //重载赋值运算符
  10. Person& operator=(Person &p)
  11. {
  12. if (m_Age != NULL)
  13. {
  14. delete m_Age;
  15. m_Age = NULL;
  16. }
  17. //编译器提供的代码是浅拷贝
  18. //m_Age = p.m_Age;
  19. //提供深拷贝 解决浅拷贝的问题
  20. m_Age = new int(*p.m_Age);
  21. //返回自身
  22. return *this;
  23. }
  24. ~Person()
  25. {
  26. if (m_Age != NULL)
  27. {
  28. delete m_Age;
  29. m_Age = NULL;
  30. }
  31. }
  32. //年龄的指针
  33. int *m_Age;
  34. };
  35. void test01()
  36. {
  37. Person p1(18);
  38. Person p2(20);
  39. Person p3(30);
  40. p3 = p2 = p1; //赋值操作
  41. cout << "p1的年龄为:" << *p1.m_Age << endl;
  42. cout << "p2的年龄为:" << *p2.m_Age << endl;
  43. cout << "p3的年龄为:" << *p3.m_Age << endl;
  44. }
  45. int main() {
  46. test01();
  47. //int a = 10;
  48. //int b = 20;
  49. //int c = 30;
  50. //c = b = a;
  51. //cout << "a = " << a << endl;
  52. //cout << "b = " << b << endl;
  53. //cout << "c = " << c << endl;
  54. system("pause");
  55. return 0;
  56. }

5 关系运算符重载

作用:重载关系运算符,可以让两个自定义类型对象进行对比操作

示例:

class Person
{
public:
    Person(string name, int age)
    {
        this->m_Name = name;
        this->m_Age = age;
    };

    bool operator==(Person & p)
    {
        if (this->m_Name == p.m_Name && this->m_Age == p.m_Age)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    bool operator!=(Person & p)
    {
        if (this->m_Name == p.m_Name && this->m_Age == p.m_Age)
        {
            return false;
        }
        else
        {
            return true;
        }
    }

    string m_Name;
    int m_Age;
};

void test01()
{
    //int a = 0;
    //int b = 0;

    Person a("孙悟空", 18);
    Person b("孙悟空", 18);

    if (a == b)
    {
        cout << "a和b相等" << endl;
    }
    else
    {
        cout << "a和b不相等" << endl;
    }

    if (a != b)
    {
        cout << "a和b不相等" << endl;
    }
    else
    {
        cout << "a和b相等" << endl;
    }
}


int main() {

    test01();

    system("pause");

    return 0;
}

6 函数调用运算符重载

  • 函数调用运算符 () 也可以重载
  • 由于重载后使用的方式非常像函数的调用,因此称为仿函数
  • 仿函数没有固定写法,非常灵活

示例:

class MyPrint
{
public:
    void operator()(string text)
    {
        cout << text << endl;
    }

};
void test01()
{
    //重载的()操作符 也称为仿函数
    MyPrint myFunc;
    myFunc("hello world");
}


class MyAdd
{
public:
    int operator()(int v1, int v2)
    {
        return v1 + v2;
    }
};

void test02()
{
    MyAdd add;
    int ret = add(10, 10);
    cout << "ret = " << ret << endl;

    //匿名对象调用  
    cout << "MyAdd()(100,100) = " << MyAdd()(100, 100) << endl;
}

int main() {

    test01();
    test02();

    system("pause");

    return 0;
}