Operator Overloading: Overloading Logical Not Operator as Member Function

What is it?

Overloading the logical not operator (!) in C++ can be done to alter its behavior when applied to objects of user-defined types (such as classes). This operator returns a true value if the operand it is applied to is false, and a false value if the operand is true.

When overloaded for a user-defined type, the logical not operator can be made to return a boolean value based on any user-specified condition. This can be useful for more intuitive programming, for instance, in implementing mathematical concepts or modeling real-world entities.


Syntax

Overloading the logical not operator as a member function is done in the following manner:

class MyClass {
public:
    bool operator!() const {
        // Implementation
    }
};

Where,

  • MyClass: This is the name of the class for which the operator is being overloaded.
  • bool: The return type of the overloaded operator is boolean (true or false).



How to use it

To overload the logical not operator for a class, follow the below steps:

  1. Within the class definition, define a function named operator!().
  2. Inside this function, write the logic based on which a boolean value (true or false) will be returned.
  3. The function does not take any parameters and must return a boolean value.



Program code snippet example

#include <iostream>

class MyClass {
private:
    int value;
public:
    MyClass(int v) : value(v) {}

    // Overloading the logical not operator
    bool operator!() const {
        return value == 0;
    }
};

int main() {
    MyClass obj1(0), obj2(10);

    if (!obj1) {
        std::cout << "Object 1 has value zero." << std::endl;
    }

    if (!obj2) {
        std::cout << "Object 2 has value zero." << std::endl;
    }

    return 0;
}

Output:

Object 1 has value zero.



Example:

#include <iostream>

class Cents {
private:
    int m_cents;
public:
    Cents(int cents) { m_cents = cents; }

    bool operator!() const {
        return !m_cents;
    }

    int get_cents() const { return m_cents; }
};

int main() {
    const Cents nickle(5);

    std::cout << std::boolalpha;
    std::cout << !nickle;

    return 0;
}

Output:

false



Example:

#include <iostream>

class Cents {
private:
    int m_cents;
public:
    Cents(int cents);

    bool operator!() const;

    int get_cents() const;
};

Cents::Cents(int cents) : m_cents(cents) {
    m_cents = cents;
}

bool Cents::operator!() const {
    return !m_cents;
}

int Cents::get_cents() const {
    return m_cents;
}

int main() {
    const Cents nickle(5);

    std::cout << std::boolalpha;
    std::cout << !nickle;

    return 0;
}

Output:

false



Important to know

  • Overloading the logical not operator can be useful in cases where the 'false' condition of an object isn't naturally false in the boolean sense, but depends on the state of the object.
  • The overloaded logical not operator can't take arguments, as it's a unary operator.
  • The function should be const because the logical not operator does not modify the state of the object.



Best practices

  1. Overload operators only when it makes logical sense: The code can become confusing if operators are overloaded in a way that does not align with their traditional use or with common sense.

  2. Use const for the function: As the logical not operator should not modify the object it is invoked on, the function should be declared as const.

  3. Return type should always be boolean: Since the logical not operator traditionally returns a boolean value, the overloaded version should also return a boolean value.




Overload the logical not operator for the Integer class.