Good day,

#include <iostream> using namespace std; void f_num(int x) { cout << "int x" << endl; } void f_num(const int x) { cout << "const int x" << endl; } void f_ptr(int* x) { cout << "int* x" << endl; } void f_ptr(const int* x) { cout << "const int* x" << endl; } int main() { int* pointer = (int*)15; const int* pointer2 = (int*)15; int number = 0; const int number2 = 15; f_num(number); f_num(number2); f_ptr(pointer); f_ptr(pointer2); } 

Why is it possible for pointers to overload through the modifier parameter const, and for an object by value there.

  • Check the code. f_num is identical to f_ptr , but must be different. More specifically: do you have an int x or const int &x parameter? It's hard to answer without seeing the code you want to write. - Mark Shevchenko
  • Hm You were not mistaken about the signature void f_ptr(const int* x) ? Did you mean void f_ptr(int* const x) ? - VladD
  • It’s not clear how your code illustrates the problem. - VladD
  • one
    Copy-paste to create a Hello world example of a problem. Updated. - rikimaru2013
  • 2
    @ rikimaru2013, a good question, by the way. - andy.37

4 answers 4

In this case, for the compiler simply perceives identical

 void f_num(int x); void f_num(const int x); 

because, in fact, with such a call, a copy of the passed variable is created, and the compiler does not const create it from a const or non- const variable, it simply cannot determine which function to call. You can pass a variable by reference (without creating a copy), then it will work:

 void f_num(int &x); void f_num(const int &x); 

    Because in C ++ / C the arguments are passed to the function by value. Therefore, in terms of the calling ad code

     void f(const int); 

    and

     void f(int); 

    completely identical.

    This is not the case for the pointer:

     void f(int *ptr); 

    has the right to change the data pointed to by ptr, and

     void f(const int *ptr); // аргумент - указатель на константу int, то же, что и f(int const *ptr); 

    It does not have this right (the object pointed to by ptr is constant).

    If we talk about the constant pointer:

     void f(int * const ptr); 

    In this case, the function does not have the right to change the ptr pointer itself, while it may well change the data to which it points, but since the call still creates a copy of it - the compiler does not distinguish it from the void f(int * ptr); signature void f(int * ptr);

    In general, the const modifier acts on the “word” immediately to its left (except when it goes first — in this case, to the word) to the right. https://stackoverflow.com/questions/9779540/c-const-pointer-declaration


    By the way, for the internal implementation of the declaration f(int i) and f(const i) different:

     void f1(const int i) { i++; } 

    Will not compile, but

     void f2(int i) { i++; } 

    compiles fine.

    • Well, not that completely identical - in the second case, the implementation of the function cannot change the argument. But in terms of declaration, yes. - VladD
    • one
      @VladD, just appending the answer. - andy.37

    Standard C ++ 13.1 / (3.4)

    Parameter declarations are equivalent and / or volatile are equivalent. This is a const and volatile type-specifiers for each parameter.

    ...

    This type of parameter is not standardized; This type of parameter-specification can be used to distinguish overloaded functions declarations. 123 In particular, for any type of T, “pointer to T”, “pointer to const T”, and “pointer to volatile T”, and “reference to volatile T”.

    Dry shutter in Russian:

    Parameters that differ only in const/volatile specifiers are considered equivalent. However, only qualifiers at the external level are ignored. Specifiers hidden inside a type are essential, and can be used to resolve overload.

    • but in fact we see that for pointers cosnt did not drop and was caught. - rikimaru2013
    • Hm, what's the motivation? - VladD
    • 2
      @ rikimaru2013, because in this case the const modifier is not an "external level" modifier. The declaration const int * p reads "pointer to const integer", and not "const pointer to integer" (what is written int * const p ). This is generally, IMHO, such an intuitively unobvious part of C.'s syntax - andy.37
    • @VladD about the motivation of other respondents told :) Although sometimes excerpts from the Standard should be perceived as axioms. For example, in D you can provide an overload on const . D I do not know, just give an example. - αλεχολυτ
    • @alexolut: Yeah, when I wrote the comment, your answer was the only one. :) - VladD

    For pointers, the top-level qualifier const is also discarded and ignored.

    For example, these two ads in the demo program declare the same function.

     #include <iostream> void f( int * ); void f( int * const ); void f( int *p ) { std::cout << "*p = " << *p << std::endl; } typedef int *Ptr; int main() { int x = 10; int *p1 = &x; int * const p2 = &x; const Ptr p3 = &x; f( p1 ); f( p2 ); f( p3 ); return 0; } 

    Output to console:

     *p = 10 *p = 10 *p = 10 

    The fact is that the argument to the function is passed by value. That is, a copy of the argument is made. Therefore, it does not matter whether the source object has a qualifier const or not. Its value is used only to initialize the function parameter, which is a local variable of the function.

    The initialization of the parameter for each function call is as follows.

     int *p = p1; int *p = p2; int *p = p3; 

    If the value of the parameter is changed in the function, it will not affect the original argument. That is, the original object that was passed as an argument to the function will remain unchanged, regardless of whether it has a const qualifier or not.

    Another thing is when a pointer points to constant data. Then you need to distinguish whether you can change the data pointed to by the pointer, or can not.

    That is, when accessing data through a pointer, you are working not with a copy of the data, but with the data itself.

    By the way, if you pass a pointer by reference, that is, you do not pass a copy of the argument to the function, but, in fact, the argument itself, then there is already an overload.

    The following program demonstrates this.

     #include <iostream> void f( int * & ); void f( int * const & ); void f( int * & ) { std::cout << "int * &" << std::endl; } void f( int * const & ) { std::cout << "int * const &" << std::endl; } typedef int *Ptr; int main() { int x = 10; int *p1 = &x; int * const p2 = &x; const Ptr p3 = &x; f( p1 ); f( p2 ); f( p3 ); return 0; } 

    Its output to the console:

     int * & int * const & int * const & 

    For simplicity, consider the following example. Let there be two declarations, one of which declares a constant object.

     int x = 10; const int y = 20; 

    Then when using a view function

     void f( int x ); 

    You can pass any object declared above as an argument, since the function will only deal with a copy of the values ​​of these objects.

    If you have a function declared as

     void f( int & ); 

    or

     void f( int * ); 

    then you can use only the first declared object as an argument for these functions, such as

     f ( x ); f( &x ); 

    The function can change the object referenced by its parameter, and the object itself is not constant, it can be changed.

    But you cannot transfer to this function the second declared object, that is how it is constant. Its program loader can generally be placed in a read-only memory.

    Therefore, the second object can be used in functions where the parameter refers to constant data, as, for example.

     void f( const int & ); 

    or

     void f( const int * ); 

    Then you can write

     f ( y ); f( &y ); 

    The presence of the const qualifier means the obligation of the function not to change the object to which its parameter refers.

    Also note the ad

     const int * const 

    This ad can be represented as

     const int ( * const ) 

    You can, for example, write

     int ( * const p ) = &x; 

    The const qualifier in parentheses is the top-level qualifier. It means that the pointer itself is constant.

    A qualifier outside parentheses is the qualifier of the object referenced by the pointer.

    For links, you cannot write in the same way:

     const int & const 

    Links themselves are not constant (although for simplicity they often say a constant link, which means a link that refers to a constant object). These are the objects they refer to as constant.