2

I am reading C++ Primer and I found something really weird and hard to understand:

Record lookup(Account&);  //Record and Account are two unrelated class
Record lookup(const Account&);

So these two functions both accept non-const object (match non-const parameter function first), but only the second function can accept const object.

And from next section (const_cast and overloading) I have these code:

const string &shorterString(const string &s1, const string &s2){
   return s1.size() < s2.size() ? s1 : s2;
}   

string &shorterString(string &s1, string &s2){
   auto &r = shorterString(const_cast<const string&>(s1),
                           const_cast<const string&>(s2));
   return const_cast<string &>)(r);
}

what on earth does const_cast<const string&>(s1) mean?

As I was told:

A reference is the object, just with another name. It is neither a pointer to the object, nor a copy of the object. It is the object.

So I pass a string object to initialize a reference s1, so s1 itself is a string object, then how can it cast a string to const string& and then to match the other function?

How should understand the function call ?

shorterString(const_cast<const string&>(s1),const_cast<const string&>(s2));

Is it using a reference to initialize a reference? But since a reference is an object itself, than I am using the object which s1 refers to initialize and its a string. so again, const_cast<const string&)(s1), string to const string&?

From my point of view, if you have a string object, then you can only match the non-const reference parameter function, and there is no something like:

string s1 = "abc";
string s2 = "efg";
shorterString(const(s1), const(s2));   //no such top-level const cast

PS: when it comes to non-const and const pointer parameter, it's understandable.

In case of tedious question, I uploaded screenshots of related paragraph from the book:

  1. https://i.stack.imgur.com/ch4aO.jpg
  2. https://i.stack.imgur.com/DVxbi.jpg
  3. https://i.stack.imgur.com/rPJFC.jpg
Rick
  • 7,007
  • 2
  • 49
  • 79
  • 1
    "_then how can it cast a `string` to `const string&` and then to match the other function?_" `const_cast` can't. In the example you provided: it casts `string&` to `const string&`. – Algirdas Preidžius Apr 12 '18 at 10:14
  • @AlgirdasPreidžius I think if I try to consider reference as some kind of pointer, that this is to some extent understandable. Thanks though – Rick Apr 12 '18 at 14:37
  • @AlgirdasPreidžius hey, I discover something new. Check this: https://stackoverflow.com/questions/49800593/how-can-const-castconst-string-s-while-s-is-a-string-type . how do you explain that cast then? So it's not from `string` to `const string&` now? – Rick Apr 12 '18 at 15:36
  • Thank you for bringing this to my attention. It appears that you can use `const_cast` for more, than I previously thought. – Algirdas Preidžius Apr 12 '18 at 17:43

2 Answers2

0

There are two overloaded functions. One is designed for using with constant objects and other is designed for using with non-constant objects.

The implementation of the function for non-constant objects is built on the call of the function for constant objects.

If you remove castings of parameters then the function for non-constant objects will try to call itself recursively.

To allow the compiler to select the function for constant objects within the function for non-constant objects you have to explicitly cast the arguments using const__cast.

Also as the function for constant objects returns a constant reference while the function for non-const objects returns a non-constant reference you have to cast the return reference of the function for constant objects to non-constant reference.

So at first you have to cast arguments ro constant reference that to call the function for constant objects and then you have to cast the return reference of the function for constant objects again to non-const referencce..

Here is a demonstrative program.

#include <iostream>
#include <string>

const std::string & shorterString( const std::string &s1, const std::string &s2 )
{
    std::cout << 
        "const std::string & shorterString( const std::string &, const std::string )"
        " called\n";
    return s2.size() < s1.size() ? s2 : s1;
}   

std::string & shorterString( std::string &s1, std::string &s2 )
{
    std::cout << 
        "std::string & shorterString( std::string &, std::string )"
        " called\n";
   return const_cast<std::string &>( shorterString( const_cast<const std::string&>( s1 ),
                                                    const_cast<const std::string&>( s2 ) ) ); 
}

int main() 
{
    std::string s1 = "abc";
    std::string s2 = "efg";

    shorterString( s1, s2 );

    std::cout << std::endl;

    shorterString( const_cast<const std::string &>( s1 ), 
                   const_cast<const std::string &>( s2 ) );

    return 0;
}

Its output is

std::string & shorterString( std::string &, std::string ) called
const std::string & shorterString( const std::string &, const std::string ) called

const std::string & shorterString( const std::string &, const std::string ) called
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
0

Why deleted my previous answer? I restated how I got the confusion

Like I said, I used to think that reference and its referent are somehow the same thing. So I felt very confused about making a non-const object to match a const reference parameter.

and give an answer :

Take reference as a special kind of pointer. From that perspective, everything seems to make sense.

That's my conclusion and answer to these two related questions. It might be helpful to newbies like me.

If you really feel that's useless, then feel free to delete the whole question.

Rick
  • 7,007
  • 2
  • 49
  • 79