Operator Overloading in C++

C++运算符重载

Posted by Tao on Wednesday, March 30, 2022

本文参考自:

在C++中,我们可以为用户定义的类定义运算符。这意味着C++能够为运算符提供对自定义类的特殊意义,这种能力称为运算符重载。例如,我们可以在像String这样的类中重载运算符“+”,这样我们就可以通过使用 + 来连接两个字符串。复数、小数、大整数中算术运算符也可能被重载。

A simple and complete example

#include <iostream>
using namespace std;

class Complex
{
private:
    int real, imag;

public:
    Complex(int r = 0, int i = 0)
    {
        real = r;
        imag = i;
    }

    // This is automatically called when '+' is used with
    // between two Complex objects
    Complex operator+(Complex const &obj)
    {
        Complex res;
        res.real = real + obj.real;
        res.imag = imag + obj.imag;
        return res;
    }
    void print() { cout << real << " + i" << imag << '\n'; }
};

int main()
{
    Complex c1(10, 5), c2(2, 4);
    Complex c3 = c1 + c2;
    c3.print();
}

Output:

12 + i9

What is the difference between operator functions and normal functions?

运算符函数和普通函数有什么区别?
呃。。。运算符函数和普通函数没什么区别。唯一的区别是运算符函数的名称始终是operator关键字后面跟运算符符号,并且通过运算符符号调用(调用时省略operator)。
下例为全局运算符函数:

#include <iostream>
using namespace std;

class Complex
{
private:
    int real, imag;

public:
    Complex(int r = 0, int i = 0)
    {
        real = r;
        imag = i;
    }
    void print() { cout << real << " + i" << imag << '\n'; }

    // The global operator function is made friend of this class so
    // that it can access private members
    friend Complex operator+(Complex const &, Complex const &);
};

Complex operator+(Complex const &c1, Complex const &c2)
{
    return Complex(c1.real + c2.real, c1.imag + c2.imag);
}

int main()
{
    Complex c1(10, 5), c2(2, 4);
    Complex c3 = c1 + c2;
    c3.print();
    return 0;
}

Output:

12 + i9

Can we overload all operators?

所有运算符都可以重载吗?结论是No

通过以下几种类型的函数可以实现运算符重载:

  1. Member Function 成员函数
  2. Non-Member Function 非成员函数
  3. Friend Function 友元函数

下列运算符可以被重载:

+   –   *   ⁄   %   ^   &   |   ~

!   =   <   >   +=  -=  *=  ⁄=  %=

^=  &=  |=  <<  >>  <<= >>= ==  !=

<=  >=  &&  ||  ++  --  ,   ->* ->

()  []  new delete  new[]   delete[]

Example 1: Overloading ++ Operator

// CPP program to illustrate
// operators that can be overloaded
#include <iostream>
using namespace std;

class overload
{
private:
    int count;

public:
    overload()
        : count(4)
    {
    }

    void operator++() { count = count + 1; }
    void Display() { cout << "Count: " << count; }
};

int main()
{
    overload i;
    // this calls "function void operator ++()" function
    ++i;
    i.Display();
    return 0;
}

Output:

Count: 5

++运算符作用于overload类的对象时(在本例中为对象i),该函数被调用。在上述程序中,定义了void operator ++()运算符函数(在overload class内部)。此函数将i对象的count值加1。

Example 2: Overloading ++ operator i.e. pre and post increment operator

// CPP program to demonstrate the
// Difference between pre increment
// and post increment overload operator
#include <iostream>
using namespace std;

class overload
{
private:
    int count;

public:
    overload(int i)
        : count(i)
    {
    }

    overload operator++(int) { return (count++); }
    overload operator++()
    {
        count = count + 1;
        return count;
    }
    void Display() { cout << "Count: " << count << endl; }
};
// Driver code
int main()
{
    overload i(5);
    overload post(5);
    overload pre(5);

    // this calls "function overload operator ++()" function
    pre = ++i;
    cout << "results of I = ";
    i.Display();
    cout << "results of preincrement = ";
    pre.Display();
    // this call "function overload operator ++()"function
    i++; // just to show diff
    i++; // just to show diff
    post = i++;
    cout << "Results of post increment = ";
    post.Display();
    cout << "And results of i , here we see difference : "
            " ";
    i.Display();
    return 0;
}

Output:

results of I   =   Count: 6
results of preincrement   =  Count: 6
Results of post increment   =   Count: 8
And results of i , here we see difference   :   Count: 9

Example 3: Overloading [ ] operator

// CPP program to illustrate overloading the
// [ ] operator

#include <iostream>
using namespace std;
class overload
{
    int a[3];

public:
    overload(int i, int j, int k)
    {
        a[0] = i;
        a[1] = j;
        a[2] = k;
    }
    int operator[](int i) { return a[i]; }
};
int main()
{
    overload ob(1, 2, 3);
    cout << ob[1]; // displays 2
    return (0);
}

Output:

2

Example 4 : Overloading -> operator

// CPP program to illustrate
// operators that can be overloaded
#include <bits/stdc++.h>
using namespace std;

class GFG
{
public:
    int num;
    GFG(int j) { num = j; }
    GFG *operator->(void) { return this; }
};

// Driver code
int main()
{
    GFG T(5);
    GFG *Ptr = &T;

    // Accessing num normally
    cout << "T.num = " << T.num << endl;

    // Accessing num using normal object pointer
    cout << "Ptr->num = " << Ptr->num << endl;

    // Accessing num using -> operator
    cout << "T->num = " << T->num << endl;

    return 0;
}

Output:

T.num = 5
Ptr->num = 5
T->num = 5

以下运算符不可被重载:

  1. Scope Resolution Operator (::)
  2. Ternary or Conditional Operator (?:)
  3. Member Access or Dot operator (.)
  4. Pointer-to-member Operator (.*)
  5. Object size Operator (sizeof)
  6. Object type Operator(typeid)

Example 5: Overloading this .(dot) operator

.(点)运算符不能重载,如果重载会报错。

// C++ program to illustrate
// Overloading this .(dot) operator
#include <iostream>
using namespace std;

class cantover
{
public:
    void fun();
};
class X
{
    cantover *p;
    cantover &operator.() { return *p; }
    void fun();
};
void g(X &x)
{
    x.fun(); // X::fun or cantover::fun or error?
}

Output: Error

prog.cpp:12:23: error: expected type-specifier before ‘.’ token
    cantover& operator.() { return *p; }

上述程序报错,类似的,上述不能重载的运算符试图重载都会报错。

Important points about operator overloading 运算符重载的一些要点

  1. 要使运算符重载起作用,至少有一个操作数必须是用户定义的类对象。

  2. 赋值运算符(Assignment Operator):编译器自动为每个类创建一个默认赋值运算符。默认赋值运算符将右侧值赋值给左侧(在大多数情况下都可以(此行为与复制构造函数相同))。

  3. 转换运算符(Conversion Operator):我们还可以定义一种将一种类型转换为另一种类型的转换运算符。

    #include <iostream>
    using namespace std;
    class Fraction
    {
    private:
        int num, den;
    
    public:
        Fraction(int n, int d)
        {
            num = n;
            den = d;
        }
    
        // Conversion operator: return float value of fraction
        operator float() const
        {
            return float(num) / float(den);
        }
    };
    
    int main()
    {
        Fraction f(2, 5);
        float val = f;
        cout << val << '\n';
        return 0;
    }
    

    Output:

    0.4
    

    重载的转换运算符必须是成员方法。其他运算符既可以是成员方法也可以是全局方法。

  4. 任何可用单个参数调用的构造函数都可以用作转换构造函数,可以用于隐式转换到正在构造的类型。

    #include <iostream>
    using namespace std;
    
    class Point
    {
    private:
        int x, y;
    
    public:
        Point(int i = 0, int j = 0)
        {
            x = i;
            y = j;
        }
        void print()
        {
            cout << "x = " << x << ", y = " << y << '\n';
       }
    };
    
    int main()
    {
        Point t(20, 20);
        t.print();
        t = 30; // Member x of t becomes 30
       t.print();
        return 0;
    }
    

    Output:

     x = 20, y = 20
     x = 30, y = 0
    

References:
http://en.wikipedia.org/wiki/Operator_overloading

「如果这篇文章对你有用,请随意打赏」

Heisenberg Blog

如果这篇文章对你有用,请随意打赏

使用微信扫描二维码完成支付


comments powered by Disqus