Nipun
Nipun

Reputation: 2261

-Woverloaded-virtual warning for const function

I have this piece of code:

class ISerializable
{
        public:
            virtual bool operator==(const ISerializable* /*value*/) const { return false;};
            virtual bool operator!=(const ISerializable* /*value*/) const { return true;};
};

class Point2I : public ISerializable
{
        public:
            bool operator==(const Point2I& value)
            {
                return (x == value.x && y == value.y);
            }

            bool operator!=(const Point2I& value)
            {
                return !(*this == value);
            }
            public:
            int x;
            int y;
};

class Coordinate : public ISerializable
{
         public:
            virtual bool operator==(const Coordinate& value) const;
            virtual bool operator!=(const Coordinate& value) const;
};

It is causing me -Woverloaded-virtual warning on gcc compiler.

I understand this warning due to that function declaration in Point2I hides virtual functions from ISerializable. But I am not sure if just missing const in Point2I can cause this warning.

Can you please help me understand if it is const which is causing this warning or something else? Warning description from gcc didn't mention anything specifically.

Update:

I found another class Coordinate in my code base which was already overriding this and gcc not throwing warning for this. Only difference in Point2I and Coordinate is I didn't declare it virtual with const in Point2I. It appears just const is hiding base class declaration.

Upvotes: 2

Views: 379

Answers (2)

Ted Lyngmo
Ted Lyngmo

Reputation: 117298

if it is const which is causing this warning or something else?

I'd say that it's something else, namely that you are not actually overriding the base class methods, even if you add const.

The argument const ISerializable* is not the same as const Point2I&.


One solution could be to override the base class methods, using const ISerializable& as the argument, and cast in the overridden methods:

class ISerializable {
public:
    // add virtual destructor if you need to delete objects through
    // base class pointers later:
    virtual ~ISerializable() = default;
    virtual bool operator==(const ISerializable&) const { return false; }
    virtual bool operator!=(const ISerializable&) const { return true; }
};

class Point2I : public ISerializable {
public:
    bool operator==(const ISerializable& value) const override {        
        auto rhs = dynamic_cast<const Point2I*>(&value);
        // rhs will be nullptr if the cast above fails
        return rhs && (x == rhs->x && y == rhs->y);
    }

    bool operator!=(const ISerializable& value) const override {
        return !(*this == value);
    }

private:
    int x = 0;
    int y = 0;
};

Example usage:

#include <iostream>

class Foo : public ISerializable {   // another ISerializable 
public:
};

int main() {
    Point2I a, b;
    std::cout << (a == b) << '\n';  // true  - using Point2I::operator==

    Foo f;
    std::cout << (a == f) << '\n';  // false - using Point2I::operator==
    std::cout << (f == a) << '\n';  // false - using ISerializable::operator==

    // this makes the default implementation in ISerializable utterly confusing:
    std::cout << (f == f) << '\n';  // false - using ISerializable::operator==
}

Another possible solution could be using CRTP but this would not work if you want to compare different types derived from ISerializable<T>:

template<class T>
class ISerializable {
public:
    virtual ~ISerializable() = default;
    virtual bool operator==(const T&) const = 0;
    virtual bool operator!=(const T&) const = 0;
};

class Point2I : public ISerializable<Point2I> {
public:
    bool operator==(const Point2I& value) const override {
        return (x == value.x && y == value.y);
    }

    bool operator!=(const Point2I& value) const override {
        return !(*this == value);
    }

public:
    int x;
    int y;
};

Upvotes: 3

Vlad from Moscow
Vlad from Moscow

Reputation: 310990

There are two problems.

The first one is different types of parameters

In these functions the parameters have the pointer type const ISerializable*

virtual bool operator==(const ISerializable* /*value*/) const { return false;};
virtual bool operator!=(const ISerializable* /*value*/) const { return true;};

and in these functions the parameters have the referenced type const Point2I&

bool operator==(const Point2I& value)
{
    return (x == value.x && y == value.y);
}

bool operator!=(const Point2I& value)
{
    return !(*this == value);
}

The second one is that the first functions are constant member functions while the second functions are not constant member functions.

Upvotes: 2

Related Questions