5

When I was writing an overide function with const parameter instead of non-const parameter, I thought the compiler would report an error, because the base function has non-const parameter, but it succeeded to compile it. Why?

My code:

#include <iostream>

class A
{
public:
    virtual uint64_t cal(uint64_t value)
    {
        std::cout << value << std::endl;
        return value;
    }
};
class B : public A
{
public:
    uint64_t cal(const uint64_t value) override;
};
uint64_t B::cal(const uint64_t value)
{
  std::cout << value + 1 << std::endl; 
  return (value+1);
}
int main()
{
    B b;
    b.cal(1);
    return 0;
}
songyuanyao
  • 169,198
  • 16
  • 310
  • 405
Carol
  • 93
  • 5
  • the cv qualifier of the parameter is ignored. – con ko Mar 04 '20 at 07:22
  • Yeah, top-level const is not part of the function signature. This is why you very often see `const` being omitted in function prototypes but only specified in the implementations, in order not to litter the API with `const` qualifiers. – Nikos C. Mar 04 '20 at 07:26
  • Also, keep in mind that `const` has somewhat weird behavior. It applies to what's on the *left* of it, not to what's on the right. But is there's nothing on the left of it, *then* (and only then) does it apply to what's on the right of it. So `const char*` is actually the same as `char const*`, but not the same as `char* const`. `char* const` is top-level const, `const char*` is **not**, because the former is a non-const pointer, the latter is a const pointer. – Nikos C. Mar 04 '20 at 07:28

3 Answers3

6

Why?

Because the top const qualifier of a function argument is ignored in a declaration.

uint64_t cal(uint64_t value);

and

uint64_t cal(const uint64_t value);

declare the exact same type of function. cal is a function taking a uint64_t and returning a uint64_t. The const qualifier makes no difference for calling code, since value is always a copy of the passed in argument.

The only difference is in the function body, where the const qualifier will prevent you from modifying the paraemter. But that is an implementation detail.

This difference can even raise coding style questions. For instance see

Is it better to remove "const" in front of "primitive" types used as function parameters in the header?

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
5

Note that top-level cv-qualifiers are dropped when considering function type, so uint64_t cal(uint64_t) and uint64_t cal(const uint64_t) are considered as the same function type.

(emphasis mine)

The type of each function parameter in the parameter list is determined according to the following rules:

4) Top-level cv-qualifiers are dropped from the parameter type (This adjustment only affects the function type, but doesn't modify the property of the parameter: int f(const int p, decltype(p)*); and int f(int, const int*); declare the same function)

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
3

Top level const of parameters is not a part of the signature of the function. The only requirement for overloading is that the signatures must match.

#include <type_traits>

int main()
{
  static_assert(std::is_same_v<int(int), int(const int)>);
}

Compiles fine

Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93