How does function overloading work in the following case? - c++

The following code compiles and runs but I'm not sure what exactly is going on at a lower level. Doesn't a reference just store the address of the object being referenced? If so, both test functions are receiving an address as a parameter? Or is the C++ implementation able to differentiate between these types in some other way?
int main() {
int i = 1;
cout << test(i) << endl;
}
char test(int &i) {
return 'a';
}
char test(int *i) {
return 'b';
}

As int& and int* are distinct types and i can be treated as a int& but not as a int*, overload resolution is absolutely unambiguous here.
It doesn't matter at this point that references are just a somewhat cloaked kind of pointer. From a language point of view they are distinct types.

References in C++ are more akin to an alias than a pointer. A reference is not a seperate variable in itself, but it is a new "name" for an exisiting variable. In your example the first test would get called because you are passing an integer to the function. A pointer is a seperate variable that holds the address of another variable so for the second function to be called you would have to call test with a pointer. Like so.. test(&i); While a tad confusing the operator & gets the address of a variable while a variable declared with an & like int &i declares a reference.

you code only matches with char test(int&i) since you are passing an int& to the function and that can not be converted to int*

Related

Assigning value to function returning reference

#include<iostream>
using namespace std;
int &fun()
{
static int x = 10;
return x;
}
int main()
{
fun() = 30;
cout << fun();
return 0;
}
Function fun() is returning value by reference but in main() method I am assigning some int to function. Ideally, a compiler should show an error like lvalue required but in above case the program works fine. Why is it so?
It's loose and sloppy language to say "a function returns something". It's OK as a shorthand if you know how to work with that, but in this case you get confused.
The more correct way to think about it is that you evaluate a function call expression. Doing that gives you a value. A value is either an rvalue or an lvalue (modulo details).
When T is an object type and you evaluate a function that has return type T, you get a value of type T which is an rvalue. On the other hand, if the function has return type T &, you get a value of type T which is an lvalue (and the value is the thing bound to the reference in the return statement).
Returning a reference is quite useful.
For example it's what std::map::operator[] does. And I hope you like the possibility of writing my_map[key] = new_value;.
If a regular (non-operator) function returns a reference then it's ok to assign to it and I don't see any reason for which this should be forbidden.
You can prevent assignment by returning a const X& or by returning X instead if you really want.
You can rewrite the code using pointers, which might be easier to understand:
#include<iostream>
using namespace std;
int *fun() //fun defined to return pointer to int
{
static int x = 10;
return &x; // returning address of static int
}
int main()
{
*fun() = 30; //execute fun(), take its return value and dereference it,
//yielding an lvalue, which you can assign to.
cout << *fun(); //you also need to dereference here
return 0;
}
References can be very confusing from a syntax point of view, as the dereferencing of the underlying "pointer" is implicitly done by the compiler for you. The pointer version looks more complicated, but is clearer or more explicit in its notation.
PS: Before someone objects to me regarding references as being a kind of pointer, the disassembly for both code versions is 100% identical.
PPS: Of course this method is a quite insidious breach of encapsulation. As others have pointed out, there are uses for this technique, but you should never do something like that without a very strong reason for it.
It works becuse the result of that function is an lvalue. References are lvalues. Basically, in the whole point of returning a non-const reference from a function is to be able to assign to it (or perform other modifications of referenced object).
In addition to other answers, consider the following code:
SomeClass& func() { ... }
func().memberFunctionOfSomeClass(value);
This is a perfectly natural thing to do, and I'd be very surprised if you expected the compiler to give you an error on this.
Now, when you write some_obj = value; what really happens behind the scenes is that you call some_obj.operator =(value);. And operator =() is just another member function of your class, no different than memberFunctionOfSomeClass().
All in all, it boils down to:
func() = value;
// equivalent to
func().operator =(value);
// equivalent to
func().memberFunctionOfSomeClass(value);
Of course this is oversimplified, and this notation doesn't apply to builtin types like int (but the same mechanisms are used).
Hopefully this will help you understand better what others have already explained in terms of lvalue.
I was buffled by similar code too - at fist. It was "why the hell I assign value to a function call, and why compiler is happy with it?" I questioned myself. But when you look at what happens "behind", it does make sense.
As cpp and others poined out, lvalues are "memory locations" that have address and we can assign values to them. You can find more on the topic of lvalues and rvalues on the internet.
When we look at the function:
int& fun()
{
static int x = 10;
return x;
}
I moved the & to the type, so it's more obvious we are returning a reference to int.
We see we have x, which is lvalue - it has address and we can assign to it. It's also static, which makes it special - if it wasn't static, the lifetime (scope) of the variable would end with stack unwinding upon leaving the function and then the reference could point to whatever black hole exists in the universe. However as x is static, it will exist even after we leave the function (and when we come back to the function again) and we can access it outside of the function.
We are returning reference to an int, and since we return x, it's reference to the x. We can then use the reference to alter the x outside of the function. So:
int main()
{
fun();
We just call the function. Variable x (in scope of fun function) is created, it has value of 10 assigned. It's address and value exist even after function is left - but we can't use it's value, since we don't have it's address.
fun() = 30;
We call the function and then change the value of x. The x value is changed via the reference returned by the function. NOTE: the function is called first and only after the function call was completed, then, the assignment happens.
int& reference_to_x = fun(); // note the &
Now we (finally) keep the reference to x returned by the function. Now we can change x without calling the function first. (reference_to_x will probably have the same address as the x have inside the fun function)
int copy_of_x = fun(); // no & this time
This time we create new int and we just copy the value of x (via the reference). This new int has its own address, it doesn't point to the x like reference_to_x is.
reference_to_x = 5;
We assigned x the value 5 through the reference, and we didn't even called the function. The copy_of_x is not changed.
copy_of_x = 15;
We changed the new int to value 15. The x is not changed, since copy_of_x have its own address.
}
As 6502 and others pointed out, we use similar approach with returning references a lot with containers and custom overrides.
std::map<std::string, std::string> map = {};
map["hello"] = "Ahoj";
// is equal to
map.operator[]("hello") = "Ahoj"; // returns reference to std::string
// could be done also this way
std::string& reference_to_string_in_map = map.operator[]("hello");
reference_to_string_in_map = "Ahoj";
The map function we use could have declaration like this:
std::string& map::operator[]( const std::string& key ); // returns reference
We don't have address to the string we "stored" in the map, so we call this overridden function of map, passing it key so map knows which string we would like to access, and it returns us reference to that string, which we can use to change the value. NOTE: again the function is called first and only after it was completed (map found the correct string and returned reference to it) the assignment happens. It's like with fun() = 10, only more beatiful...
Hope this helps anyone who still woudn't understand everything even after reading other answers...
L-value is a locator-value. It means it has address. A reference clearly has an address. The lvalue required you can get if you return from fun() by value:
#include<iostream>
using namespace std;
int fun()
{
static int x = 10;
return x;
}
int main()
{
fun() = 30;
cout << fun();
return 0;
}

function overloading with const parameters

Function overloading can happen between two member functions which have the same number of parameters, if one of them is declared as const.
But what if one function has a const argument, another has non-const argument of same type?
Will it work for references and pointers? If C++ provides it, why does it provide? Please share the reason with me if you know.
Below is the example that helps you in understanding the above scenario.
void fun(const int i)
{
cout << "fun(const int) called ";
}
void fun(int i)
{
cout << "fun(int ) called " ;
}
int main()
{
const int i = 10;
fun(i);
return 0;
}
Output: Compiler Error: redefinition of 'void fun(int)'
void fun(char *a)
{
cout<<"non-const fun() called";
}
void fun(const char *a)
{
cout<<"const fun() called";
}
int main()
{
const char *ptr = "GeeksforGeeks";
fun(ptr);
return 0;
}
Output: const fun() called
Why is the second one allowed in C++?
The first one's parameters are top-level const. This means that the function can't change the parameter's value, however, the caller doesn't care: The callee gets a copy of the argument, so if a parameter has top-level const, it's an implementation detail. Note that the following works:
void f(int); // forward declare
void g(){ f(42); }
void f(int const i){ /*...*/ } // define above declared function
For the second set of overloads, the const isn't top-level anymore. It describes whether or not the callee can change what the pointer points at. As a caller, you do care about that. It's not just an implementation detail anymore.
First, explain why the first code is not allowed while the second one is ok.
const int and int as parameter, you pass any related type, double, int or anything else can convert to int, both const int and int can accept the pass-in value, there's no difference practically. And if the complier allow to the define both, then which one to call? You don't know, neither the complier. So the first part of code is not allowed.
When it comes to second example, reference and pointer makes a difference. Because you can't pass a const int* to initialize int * and neither can use const int to initialize int&. So if you define two functions with same return type, one is "const version" pointer or reference parameter, and the other is not, that makes a difference. Another question comes up, what if I pass a int object(or called variable, same meaning) or int * pointer, then which one is matched (when parameters are pointer or reference)? The answer is the "non-const" one. if you want to match the "const version" with non-const object or non point to const pointer, you may need const_cast which I am trying to figure out.
So back to your question:
But what if one function has a const argument, another has non-const argument of same type? Will it work for references and pointers?
Yes, it to some extent only works for reference and pointers.
And
If C++ provides it, why does it provide?
Can't tell. I don't have much experience.
For further information, read the very related part sections of C++ Primer 5th.
Links of screenshots are listed as follows:
https://imgur.com/tnqrxVY
https://imgur.com/hF1MjUH
https://imgur.com/Fg2zeEw
By the way, though I am a newbie. But what is int const i from the first answer? And I don't understand what "it's an implementation detail" exactly mean. No offense, just can't understand that part of answer. :D

return type in c++

#include<iostream>
int & fun();
int main()
{
int p = fun();
std::cout << p;
return 0;
}
int & fun()
{
int a=10;
return a;
}
Why is this program not giving error at line no.6 as "invalid conversion from int* to int", as it happens in case we do like this?
int x = 9;
int a = &x;
int& is a type; it means "a reference to int."
&x is an expression; it means "take the address of x." The unary & operator is the address operator. It takes the address of its argument. If x is an int, then the type of &x is "a pointer to int" (that is, int*).
int& and int* are different types. References and pointers are the same in many respects; namely, they both refer to objects, but they are quite different in how they are used. For one thing, a reference implicitly refers to an object and no indirection is needed to get to the referenced object. Explicit indirection (using * or ->) is needed to get the object referenced by a pointer.
These two uses of the & are completely different. They aren't the only uses either: for example, there is also the binary & operator that performs the bitwise and operation.
Note also that your function fun is incorrect because you return a reference to a local variable. Once the function returns, a is destroyed and ceases to exist so you can never use the reference that is returned from the function. If you do use it, e.g. by assigning the result of fun() to p as you do, the behavior is undefined.
When returning a reference from a function you must be certain that the object to which the reference refers will exist after the function returns.
Why is this program not giving error at line no.5 as "invalid conversion from int* to int", as it happens in case we do like this?
That's because you are trying to return the variable by reference and not by address. However your code invokes Undefined Behaviour because returning a reference to a local variable and then using the result is UB.
Because in one case its a pointer and in the other a reference:
int a=&x means set a to the address of x - wrong
int &p=fun() means set p to a reference to an int - ok
Functions in C++ are not same as macros i.e. when you qrite int p = fun() it doesn't become int p = &a; (I guess that is what you are expecting from your question). What you are doing is returning a reference from the function f. You are no where taking address of any variable. BTW, the above code will invoke undfeined behavior as you are returning a reference to the local variable.
You're not returning an int *, you're retuning an int &. That is, you're returning a reference to an integer, not a pointer. That reference can decay into an int.
Those are two different things, although they both use the ampersand symbol. In your first example, you are returning a reference to an int, which is assignable to an int. In your second example, you are trying to assign the address of x (pointer) to an int, which is illegal.

pointer reference type

I am trying to write a function that takes a pointer argument, modifies what the pointer points to, and then returns the destination of the pointer as a reference.
I am getting the following error: cannot convert int*** to int* in return
Code:
#include <iostream>
using namespace std;
int* increment(int** i) {
i++;
return &i;
}
int main() {
int a=24;
int *p=&a;
int *p2;
p2=increment(&p);
cout<<p2;
}
Thanks for helping!
If you indeed mean "return the destination of the pointer as a reference", then I think the return type you're after is int& rather than int*.
This can be one of the confusing things about C++, since & and * have different meanings depending on where you use them. & is "Reference type" if you're talking about a variable definition or return type; but it means "Address of" if it's in front of a variable being used after it's defined.
I could be completely mistaken, but it seems to me that you've gotten these two meanings mixed up; and since you want to return a reference, you've written "return &i", since & is used for references. However, in this case, it returns the address of i. And since i is a pointer to a pointer to an int, in this line of code:
int* increment(int** i) { i++; return &i;}
you are returning the address of a pointer to a pointer to an int. That is why you are getting your error message cannot convert int***' to int*.
Let's walk through your code line by line. You are after a program that takes a pointer and returns a reference. So that would be:
int& increment(int* i)
We don't need the double pointer that you had in your code (unless you want a pointer to a pointer). Then you want it to modify what the pointer points to:
(*i)++;
And then return the destination of the pointer as a reference:
return *i;
Here, we are dereferencing i. Remember that using references lets you treat them like normal variables, and handles the pointer stuff for you. So C++ will figure out that you want it to be a reference.
Then, to use your code, you can do pretty much what you had, but using less pointers:
int a=24;
int *p=&a;
int *p2;
p2 = increment(p);
I haven't tested any of this, so anyone may feel free to edit my answer and fix it if I've got something wrong.
int* increment(int** i) { (**i)++; return *i;}
and
cout << *p2;

What does '&' do in a C++ declaration?

I am a C guy and I'm trying to understand some C++ code. I have the following function declaration:
int foo(const string &myname) {
cout << "called foo for: " << myname << endl;
return 0;
}
How does the function signature differ from the equivalent C:
int foo(const char *myname)
Is there a difference between using string *myname vs string &myname? What is the difference between & in C++ and * in C to indicate pointers?
Similarly:
const string &GetMethodName() { ... }
What is the & doing here? Is there some website that explains how & is used differently in C vs C++?
The "&" denotes a reference instead of a pointer to an object (In your case a constant reference).
The advantage of having a function such as
foo(string const& myname)
over
foo(string const* myname)
is that in the former case you are guaranteed that myname is non-null, since C++ does not allow NULL references. Since you are passing by reference, the object is not copied, just like if you were passing a pointer.
Your second example:
const string &GetMethodName() { ... }
Would allow you to return a constant reference to, for example, a member variable. This is useful if you do not wish a copy to be returned, and again be guaranteed that the value returned is non-null. As an example, the following allows you direct, read-only access:
class A
{
public:
int bar() const {return someValue;}
//Big, expensive to copy class
}
class B
{
public:
A const& getA() { return mA;}
private:
A mA;
}
void someFunction()
{
B b = B();
//Access A, ability to call const functions on A
//No need to check for null, since reference is guaranteed to be valid.
int value = b.getA().bar();
}
You have to of course be careful to not return invalid references.
Compilers will happily compile the following (depending on your warning level and how you treat warnings)
int const& foo()
{
int a;
//This is very bad, returning reference to something on the stack. This will
//crash at runtime.
return a;
}
Basically, it is your responsibility to ensure that whatever you are returning a reference to is actually valid.
Here, & is not used as an operator. As part of function or variable declarations, & denotes a reference. The C++ FAQ Lite has a pretty nifty chapter on references.
string * and string& differ in a couple of ways. First of all, the pointer points to the address location of the data. The reference points to the data. If you had the following function:
int foo(string *param1);
You would have to check in the function declaration to make sure that param1 pointed to a valid location. Comparatively:
int foo(string &param1);
Here, it is the caller's responsibility to make sure the pointed to data is valid. You can't pass a "NULL" value, for example, int he second function above.
With regards to your second question, about the method return values being a reference, consider the following three functions:
string &foo();
string *foo();
string foo();
In the first case, you would be returning a reference to the data. If your function declaration looked like this:
string &foo()
{
string localString = "Hello!";
return localString;
}
You would probably get some compiler errors, since you are returning a reference to a string that was initialized in the stack for that function. On the function return, that data location is no longer valid. Typically, you would want to return a reference to a class member or something like that.
The second function above returns a pointer in actual memory, so it would stay the same. You would have to check for NULL-pointers, though.
Finally, in the third case, the data returned would be copied into the return value for the caller. So if your function was like this:
string foo()
{
string localString = "Hello!";
return localString;
}
You'd be okay, since the string "Hello" would be copied into the return value for that function, accessible in the caller's memory space.
Your function declares a constant reference to a string:
int foo(const string &myname) {
cout << "called foo for: " << myname << endl;
return 0;
}
A reference has some special properties, which make it a safer alternative to pointers in many ways:
it can never be NULL
it must always be initialised
it cannot be changed to refer to a different variable once set
it can be used in exactly the same way as the variable to which it refers (which means you do not need to deference it like a pointer)
How does the function signature differ from the equivalent C:
int foo(const char *myname)
There are several differences, since the first refers directly to an object, while const char* must be dereferenced to point to the data.
Is there a difference between using string *myname vs string &myname?
The main difference when dealing with parameters is that you do not need to dereference &myname. A simpler example is:
int add_ptr(int *x, int* y)
{
return *x + *y;
}
int add_ref(int &x, int &y)
{
return x + y;
}
which do exactly the same thing. The only difference in this case is that you do not need to dereference x and y as they refer directly to the variables passed in.
const string &GetMethodName() { ... }
What is the & doing here? Is there some website that explains how & is used differently in C vs C++?
This returns a constant reference to a string. So the caller gets to access the returned variable directly, but only in a read-only sense. This is sometimes used to return string data members without allocating extra memory.
There are some subtleties with references - have a look at the C++ FAQ on References for some more details.
#include<iostream>
using namespace std;
int add(int &number);
int main ()
{
int number;
int result;
number=5;
cout << "The value of the variable number before calling the function : " << number << endl;
result=add(&number);
cout << "The value of the variable number after the function is returned : " << number << endl;
cout << "The value of result : " << result << endl;
return(0);
}
int add(int &p)
{
*p=*p+100;
return(*p);
}
This is invalid code on several counts. Running it through g++ gives:
crap.cpp: In function ‘int main()’:
crap.cpp:11: error: invalid initialization of non-const reference of type ‘int&’ from a temporary of type ‘int*’
crap.cpp:3: error: in passing argument 1 of ‘int add(int&)’
crap.cpp: In function ‘int add(int&)’:
crap.cpp:19: error: invalid type argument of ‘unary *’
crap.cpp:19: error: invalid type argument of ‘unary *’
crap.cpp:20: error: invalid type argument of ‘unary *’
A valid version of the code reads:
#include<iostream>
using namespace std;
int add(int &number);
int main ()
{
int number;
int result;
number=5;
cout << "The value of the variable number before calling the function : " << number << endl;
result=add(number);
cout << "The value of the variable number after the function is returned : " << number << endl;
cout << "The value of result : " << result << endl;
return(0);
}
int add(int &p)
{
p=p+100;
return p;
}
What is happening here is that you are passing a variable "as is" to your function. This is roughly equivalent to:
int add(int *p)
{
*p=*p+100;
return *p;
}
However, passing a reference to a function ensures that you cannot do things like pointer arithmetic with the reference. For example:
int add(int &p)
{
*p=*p+100;
return p;
}
is invalid.
If you must use a pointer to a reference, that has to be done explicitly:
int add(int &p)
{
int* i = &p;
i=i+100L;
return *i;
}
Which on a test run gives (as expected) junk output:
The value of the variable number before calling the function : 5
The value of the variable number after the function is returned : 5
The value of result : 1399090792
One way to look at the & (reference) operator in c++ is that is merely a syntactic sugar to a pointer. For example, the following are roughly equivalent:
void foo(int &x)
{
x = x + 1;
}
void foo(int *x)
{
*x = *x + 1;
}
The more useful is when you're dealing with a class, so that your methods turn from x->bar() to x.bar().
The reason I said roughly is that using references imposes additional compile-time restrictions on what you can do with the reference, in order to protect you from some of the problems caused when dealing with pointers. For instance, you can't accidentally change the pointer, or use the pointer in any way other than to reference the singular object you've been passed.
In this context & is causing the function to take stringname by reference.
The difference between references and pointers is:
When you take a reference to a variable, that reference is the variable you referenced. You don't need to dereference it or anything, working with the reference is sematically equal to working with the referenced variable itself.
NULL is not a valid value to a reference and will result in a compiler error. So generally, if you want to use an output parameter (or a pointer/reference in general) in a C++ function, and passing a null value to that parameter should be allowed, then use a pointer (or smart pointer, preferably). If passing a null value makes no sense for that function, use a reference.
You cannot 're-seat' a reference. While the value of a pointer can be changed to point at something else, a reference has no similar functionality. Once you take a variable by reference, you are effectively dealing with that variable directly. Just like you can't change the value of a by writing b = 4;. A reference's value is the value of whatever it referenced.