📜 ⬆️ ⬇️

The subtleties of overloading methods by constancy * this

dress11.jpg - image uploaded to Picamatic I discovered that there is an aspect of C ++ that I hadn’t thought about before. Namely: if you have two implementations of the same method (overload), differing in the constancy of * this:
int & v ();
const int & v () const ;
when and what method will be called?

Let there be both methods: both const and non-const

Immediately combat example:
#include <iostream><br><br> class A {<br> public :<br> int val;<br> A( int x): val(x) {}<br> int & v() {<br> std::cout << "v()" << std::endl;<br> return val;<br> }<br> const int & v() const {<br> std::cout << "v() const" << std::endl;<br> return val;<br> }<br>};<br><br> int main() {<br> std::cout << "test 1" << std::endl;<br> A x(1);<br> std::cout << "x.val = " << x.val << std::endl;<br> xv() = 3;<br> std::cout << "x.val = " << x.val << std::endl;<br><br> std::cout << "test 2" << std::endl;<br> A const y(2);<br> int a = xv();<br> int const b = xv();<br> int c = yv();<br> int const d = yv();<br>}<br> <br> * This source code was highlighted with Source Code Highlighter .
It turns out he gives:

 test 1
 x.val = 1
 v ()
 x.val = 3
 test 2
 v ()
 v ()
 v () const
 v () const

Actually, the work of the first test is clear, we will return to it later. In this context, the work of the second test is more interesting. It can be seen that when choosing a const / non-const variant of the v () method, C ++ takes into account not the constancy of the desired result, but the constancy of the object for which the method is called.
')
If you think about it, then this behavior turns out to be quite logical. The fact is that the signature of the method does not include the constancy of the return value, for some reason it includes the constancy of * this. Thus, at the time of the call, the return value does not determine which method will be called. For some reason, the compiler knows about the constancy of x and y, that is, it knows about the constancy of * this for x and y, and it can use this criterion to choose a modification of the v () method.

What happens if there is no overload?

What happens if we implement only the non-const method?


That is, our class looks like this:

class A {<br> public :<br> int val;<br> A( int x): val(x) {}<br> int & v() {<br> std::cout << "v()" << std::endl;<br> return val;<br> }<br>}; <br> <br> * Source Code Highlighter .

Well, our code will not compile. To work with the variable y, we will miss the method, for the constant * this.

And if we implement only the const method?


class A {<br> public :<br> int val;<br> A( int x): val(x) {}<br> const int & v() const {<br> std::cout << "v()" << std::endl;<br> return val;<br> }<br>}; <br><br> * This source code was highlighted with Source Code Highlighter .

Then all the assignments (the second test) will work fine and will use the constant method. But the first test, of course, will not work. If you do not need this functionality (and it is not always needed), then you may not need to implement non-const methods.

And why is all this necessary?


Why you need to decide this :-) But Qt containers made me think about it (many other containers were made the same way, just somehow I hadn’t paid attention to this feature before). For example, the QList container has four methods of accessing an item by index:

const T & at ( int i) const ;<br>T value ( int i) const ;<br>T & operator [] ( int i);<br> const T & operator [] ( int i) const ; <br><br> * This source code was highlighted with Source Code Highlighter .

Among them there are very similar (compare the first and last). After the above thoughts, it became clear to me why such redundancy was made, when which method should be used and when which of the overloaded methods is used. I hope the reader is now also clear.

Successes to all!

Source: https://habr.com/ru/post/76065/


All Articles