Search code examples
c++inheritancepolymorphismoperator-overloadingmultiple-inheritance

C++: Function call precedence rules for calling functions on objects of derived classes?


I have a class Iterator, for which I have defined various operator overloads for equality testing (<, <=, >, >=, == and !=) as friend functions. Prototype example:

friend bool operator<(const Iterator &A, const Iterator &B);

class RevIterator inherits (virtually) from Iterator. Naturally, I have had to overload the operators <, <=, > and >= for this class (as friend functions again). Prototype example:

friend bool operator<(const RevIterator &A, const RevIterator &B);

I also have a class ConstIterator which inherits (virtually) from Iterator, for which I have not defined more operator overloads (they are meant to behave in the same way as for Iterator).

Finally, I have a class ConstRevIterator which inherits from RevIterator and ConstIterator, for which I have not defined any operator overloads.

Visual class hierarchy:

class Iterator {};
class RevIterator : virtual public Iterator {};
class ConstIterator : virtual public Iterator {};
class ConstRevIterator : public RevIterator, public ConstIterator {};

My assumption was that for the operator <, for example, operating on two ConstRevIterators, the function available for one of the parent classes, RevIterator (2nd func. prototype above) would be called, instead of the function for the grandparent class, Iterator (1st func. prototype above).

In summary, what are the rules for which function gets called on a reference to a 'grandchild' object, when there are functions available for its parent and grandparent classes?


Solution

  • Your assumption seems correct. You may find rules of overload resolution here https://en.cppreference.com/w/cpp/language/overload_resolution

    Here is the part concerning your question:

    1. If Mid is derived (directly or indirectly) from Base, and Derived is derived (directly or indirectly) from Mid

    a) Derived* to Mid* is better than Derived* to Base*

    b) Derived to Mid& or Mid&& is better than Derived to Base& or Base&&

    c) Base::* to Mid::* is better than Base::* to Derived::*

    d) Derived to Mid is better than Derived to Base

    e) Mid* to Base* is better than Derived* to Base*

    f) Mid to Base& or Base&& is better than Derived to Base& or Base&&

    g) Mid::* to Derived::* is better than Base::* to Derived::*

    h) Mid to Base is better than Derived to Base

    I also produced some code to verify it: https://godbolt.org/z/bc47dzxvY