kopiro
kopiro

Reputation: 709

C++ - const keyword in methods and overload

for which reason this program:

#include <iostream>
using namespace std;
class Base {
public:
  Base() { cout << "Costruttore Base" << endl; }
  virtual void foo(int) { cout << "Base::foo(int)" << endl; }
  virtual void bar(int) { cout << "Base::bar(int)" << endl; }
  virtual void bar(double) { cout << "Base::bar(double)" << endl; }
  virtual ~Base() { cout << "Distruttore Base" << endl; }
};
class Derived : public Base {
public:
  Derived() { cout << "Costruttore Derived" << endl; }
  void foo(int) { cout << "Derived::foo(int)" << endl; }
  void bar(int) const { cout << "Derived::bar(int)" << endl; }
  void bar(double) const { cout << "Derived::bar(double) const" << endl; }
  ~Derived() { cout << "Distruttore Derived" << endl; }
};
int main() {
  Derived derived;
  Base base;
  Base& base_ref = base;
  Base* base_ptr = &derived;
  Derived* derived_ptr = &derived;
  cout << "=== 1 ===" << endl;
  base_ptr->foo(12.0);
  base_ref.foo(7);
  base_ptr->bar(1.0);
  derived_ptr->bar(1.0);
  derived.bar(2);
  return 0;
}

In the call base_ptr->bar(1.0); is called Base::bar(double), instead in the derived_ptr->bar(1.0); is called Derived::bar(double) const.

I understood that is about the const keyword, but I don't understand why the compiler is choosing different overloaded functions.

If I remove the const keyword, everything is working as expected, calling in both cases the Derived::bar

Upvotes: 4

Views: 365

Answers (3)

WhiZTiM
WhiZTiM

Reputation: 21576

C++11 added the override specifier to prevent these kind of surprises. Use, the override keyword, and the compiler will only compile your code, if it does override.

Taking the supposedly override of bar(int) (this also applies to the bar(double):

class Base {
public:
  ....
  virtual void bar(int) { cout << "Base::bar(int)" << endl; }
};

class Derived : public Base {
public:
  ...
  //This isn't an override, program is well formed
  void bar(int) const { cout << "Derived::bar(int)" << endl; }
};

The bar member function in Derived did not override the base class' own. Because the const qualifications are different, hence the member function signatures are different. All you did in the derived class was to add a new overload and hide that of the base class'.

Add the override keyword in the derived class' and the compiler will give a diagnostic if it doesn't override.

class Base {
public:
  ....
  virtual void bar(int) { cout << "Base::bar(int)" << endl; }
};

class Derived : public Base {
public:
  ...
  //This isn't an override, program is ill-formed, diagnostic required
  void bar(int) const override { cout << "Derived::bar(int)" << endl; }
};

To override, the member function signatures must be the same.

class Base {
public:
  ....
  virtual void bar(int) { cout << "Base::bar(int)" << endl; }
};

class Derived : public Base {
public:
  ...
  //This overrides
  void bar(int) override { cout << "Derived::bar(int)" << endl; }
};

So, learn to use the override keyword whenever you want to override, it will save you some headaches.

Upvotes: 2

RoaaGharra
RoaaGharra

Reputation: 710

It's because you're not really overriding the function bar(). You are defining a new function bar() in the derived class with a different signature.

So either remove the const in the derived class or add a const to the signature of bar() in the upper class. (Or keep it as it is but know that you now have two functions named bar() in derived class, one of which is hidden)

Upvotes: 2

Paul Evans
Paul Evans

Reputation: 27577

That's because const changes the signature of the function, so they're different. Either make both the base class and derived class const or not, otherwise one won't override the other.

Upvotes: 3

Related Questions