Event Driven Programming: Operator Overloading

Event Driven Programming: Operator Overloading

Basic Information

Different between override and overload

Override and overload are all about polymorphism.

Override Overload
Location Superclass and Subclass In the same class
Feature Must has same name, return value, parameter list as superclass All function have the same name but different parameter list and return value

Two ways to overloading operators

non-static member function non-member function
(),[],->and any assignment operator must be overload as class member one of the parameter must be an object class
Binary operator with one parameter with two parameter
Unary operator With no parameter With one parameter

The parameter is the operand beside the operator.

The function name must start as operator, such as operator+(),operator-()and operator[]().

Other Attention

Three operator is exceptions:

  1. Assignment operator(=)
    1. It default memberwise assignment for "source" to "target".
    2. If object has pointer member, that will be dangerous.
    3. Most of the time we will overloading assignment operator.
  2. Address operator(&)
    1. It will return a pointer to the object.
    2. It also can be overload.
  3. Comma operator(,)
    1. From left to right evaluation the expression and return the result that the last expression’s value.

Four operator are not be overloaded:. | .* | :: | ?:.

Three feature cannot be changed:

  1. Precedence of operator.
  2. Associativity of operator.
  3. The "arity" of operator.
    1. "arity" means arguments number.
    2. Binary just be overload as binary.
    3. Unary just be overload as unary.

Four special operator, they have both binary and unary version: &, *, +, -

Attention:

  1. Cannot create new operator.
  2. Cannot change the meaning of how an operator works on values of fundamental types.
    1. Such as you cannot overload the + to implement the subtract(-).
  3. + and += is two different operator, should be overload separately.

Simple Operator Overloading

Binary operator

non-static member function non-member function
with one argument with two argument

Example

Here is an example about the operator + and = overloading by non-static member function .

#include <bits/stdc++.h>
using namespace std;

class mySecond
{
public:
    int sec;
    int usec;
    mySecond operator+(mySecond const &other)
    {
        mySecond temp = *this;// copy object
        temp.sec += other.sec;
        temp.usec += other.usec;
        return temp;// return the copy
    }
    // const is in order to enable the (a=b=c) but deny the (a=b)=c
    const mySecond &operator=(mySecond const &other)
    {
        sec = other.sec;
        usec = other.usec;
        return *this;
    }
};

int main()
{
    mySecond A;
    A.sec = 0;
    A.usec = 100;
    
    mySecond B;
    B.sec = 100;
    B.usec = 0;

    A = A + B;
    
    cout << A.sec << " " << A.usec << endl;
    return 0;
}

Output:

100 100

If you want to overloading other operators, just follow this format.
But you need attention to the return value of overloading.

Processing of Overloading Invoke

Object a,b;
a=a+b;

As the code, it will be generate by compiler to:

a.operator=(a.operator=(b));

If overloading by non-member function:

operator=(a,operator+(a,b));

Return Value

Different operator have different return values, it has special purpose.

For example:

mySecond operator+(mySecond const &other)
const mySecond &operator=(mySecond const &other)

operator+ return a vairable by value, but operator= return a const variable by reference.

As we all know, if you just add two value but not assignment, the result will not be stored, and the value of a or b are not change too.

int a=1,b=1;
a+b;

So, as the concrete realization, we copy the object at first. And then, all operations are done on this copy, we return the copy at the end.

For operator=, the aim we use the = is change the value of left operand, so we can directly change the value of object, instead of copying.

Benefits of return reference:

  1. Improve performance.
  2. Help cascaded invoke.(Such as stream operator).
  3. The result can be modified.

If you do not to change the result, just add a const.(Like the operator=).

Why we need non-member function?

As we all know, if the operator is overloaded, the expression will generate Object.operator+( rightOperand ).
The Object is left operand, so the program can invoke the member function in the Object.
But when the left operand is fundamental type or the Object is not the same class with right operand, the non-member function is useful.
Consider this example:

Object temp;
temp = 10 + temp;

10 is a fundamental type constant, it don’t have the member function operator+(), in this case the program will find the operator+() in global scope.
If there no non-member function declared, the error will occured.

In short, all the operator overloading in left operand should be declared as non-member function.

Stream Operator is a typically example of non-member function.

Stream Operator Overloading

Stream insertion operator << and stream extraction operator >> .

Some function in stream

Function name setw() ignore()
Description Limits the number of characters read into each string Which discards the specified number of characters in the input stream

The process of stream operator was used

If we overload the operator << and >>, when the program use the cin>>object, the compiler will generate the non-member functino call(cout<< is same) :

operator>>(cin, object)

This function will return a istream reference, so you can cascaded with other object.

Operand

If we use << >>:

Left operand Right operand
ostream & or istream & user-defined class

friend keyword

friend can make the non-member function access the private member of class.
friend function should be declared in the class member function list (but friend function is not member function).

In the stream operator, the left operand is cin operator , the compiler will generate the non-member function operator>>(cin, object).
This is a global funciton, the function cannot access the private member of object, if it access the private member, the program will occur the error.

In order to access the private member, we should declare as the friend function.

But, if you through the accessor and mutator function to access the private member, the friend is not necessary.

With friend

class mySecond
{
public:
    mySecond(int a = 10, int b = 10)
    {
        sec = a;
        usec = b;
    }
    friend ostream &operator<<(ostream &out, mySecond &other);

private:
    int sec;
    int usec;
};

ostream &operator<<(ostream &out, mySecond &other)
{
    out << "sec=" << other.sec << "\nusec=" << other.usec << endl;
    return out;
}

int main()
{
    mySecond A(0, 100);
    cout << A << endl;

    return 0;
}

Without friend

class newSecond : public mySecond
{
public:
    newSecond(int a = 10, int b = 10) : mySecond(a, b)
    {
    }
    int getSec()
    {
        return mySecond::getSec();
    }
    int getUsec()
    {
        return mySecond::getUsec();
    }
};

ostream &operator<<(ostream &out, newSecond &other)
{
    out << "sec=" << other.getSec() << "\nusec=" << other.getUsec() << endl;
    return out;
}

int main()
{
    newSecond A(0, 100);
    cout << A << endl;
    
    return 0;
}

Unary operator

non-static member function non-member function
with no argument with one argument
Must be an object (or reference of object)

Using reference?
If parameter is reference, it will efffect the original object.

Prefix and Postfix with ++ and --

Prefix and postfix are allowed overload in the same class(at the same time), but you should use the distinct signature to recognize them.

Difference between prefix and postfix:

Prefix Postfix
As same as the othe unary operator Have a convention
non-static member function will generates d1.operator++() will generates d1.operator++(0)
Prototype Date &operator++() Date &operator++( int )
non-member function will generate operator++(d1) will generates operator++( d1, 0 )
Prototype Date operator++( Date & ) Date operator++( Date &, int )
Return value return by reference return by value
The value is a temporary object that contains is the original value befor increment

Example:

#include <bits/stdc++.h>
using namespace std;
class mySecond
{
public:
    int sec;
    int usec;
    mySecond(int a = 10, int b = 10)
    {
        sec = a;
        usec = b;
    }
    mySecond &operator++()
    {
        usec += 1;
        return *this;
    }
    mySecond operator++(int)
    {
        mySecond temp = *this;
        usec += 1;
        return temp;
    }
};

int main()
{
    mySecond A(0, 100);
    mySecond B(0, 100);
    cout << (A++).usec << endl;
    cout << A.usec << endl;
    cout << (++B).usec << endl;
    cout << B.usec << endl;
    return 0;
}

Why the return value is different?:
As we all know, a++ is first use last increment, ++a is first increment last use:

int a;

a=0;
int b=a++;
a=0
int c=++a;

The result of code is b=0,c=1.

If we use the ++a, we need return the value that is incremented, but a++ we need return the value before increment.
So in postfix, we copy the value be increment, and at last return it.

One sentence:
When we define the function, we should set different signature to distinguish the prefix and postfix.(postfix is one more parameter than prefix (a dummy value))

Attention:

  1. Postfix will create a temporary object, so it will cause the performance problem.
  2. When we overloading the operator, we should set the right return value.
    • Prefix return a reference.
    • Postfix return a value.

评论

  1. 谦人
    2 年前
    2023-6-07 23:28:51

    你小子 可以!

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇