this is a const ptr to the object/instance which a member function receive implicitly, so how does return *this returns a reference ?
As of what I know , a pointer dereferencing to a variable means it holds it's memory address , so return *this should return value dereferenced by this const pointer which is what? An object?
Also, why you can't do something like this:
Calc cCalc;
cCalc.Add(5).Sub(3).Mult(4);
Without having all that member functions to return *this?
I would want to know how pointers and reference treat objects/instances.
Let's try to untangle:
this is a const ptr to the object/instance which a member function receive implicitly
member functions indeed receive this pointer implicitly. The type is T* or const T* depending on the member function signature -- you get const placing const keyword at the tail after the ().
so how does return *this returns a reference ?
*this dereference the pointer, thus creating lvalue of type T or const T respectively. If your question is meant how you get T& from *this in a const funstion, the answer that you don't, that attempt would be ill-formed code.
As of what I know , a pointer dereferencing to a variable means it holds it's memory address , so return *this should return value dereferenced by this const pointer which is what? An object?
*this denotes the instance. And it is lvalue expression. So you can get its address agan (providing same as this), or can bind it to a reference -- including the case for a return.
The chaining you show can actually be done if the functions returned Calc instead of Calc& or returned some different object than *this -- but then the result of calculations would end up in that place. Not where you expect it: in cCalc.
As it stands, when all three functions return *this leads first Add taking &cCalc in this, and returns cCalc. The next call to Sub has the same situation. And Multiply too.
Add member doesnt have Sub function. Compiler give an error.
But, if you return *this, you are returning your own object (not reference). Now you have one cCalc object that can use Sub(3). Sub(3) return your object and can use Mult(4).
Related
I'm learning C++ and pointers and I thought I understood pointers until I saw this.
On one side the asterix(*) operator is dereferecing, which means it returns the value in the address the value is pointing to, and that the ampersand (&) operator is the opposite, and returns the address of where the value is stored in memory.
Reading now about assignment overloading, it says "we return *this because we want to return a reference to the object". Though from what I read *this actually returns the value of this, and actually &this logically should be returned if we want to return a reference to the object.
How does this add up? I guess I'm missing something here because I didn't find this question asked elsewhere, but the explanation seems like the complete opposite of what should be, regarding the logic of * to dereference, & get a reference.
For example here:
struct A {
A& operator=(const A&) {
cout << "A::operator=(const A&)" << endl;
return *this;
}
};
this is a pointer that keeps the address of the current object. So dereferencing the pointer like *this you will get the lvalue of the current object itself. And the return type of the copy assignment operator of the presented class is A&. So returning the expression *this you are returning a reference to the current object.
According to the C++ 17 Standard (8.1.2 This)
1 The keyword this names a pointer to the object for which a
non-static member function (12.2.2.1) is invoked or a non-static data
member’s initializer (12.2) is evaluated.
Consider the following code snippet as an simplified example.
int x = 10;
int *this_x = &x;
Now to return a reference to the object you need to use the expression *this_x as for example
std::cout << *this_x << '\n';
& has multiple meanings depending on the context. In C and used alone, I can either be a bitwise AND operator or the address of something referenced by a symbol.
In C++, after a type name, it also means that what follows is a reference to an object of this type.
This means that is you enter :
int a = 0;
int & b = a;
… b will become de facto an alias of a.
In your example, operator= is made to return an object of type A (not a pointer onto it). This will be seen this way by uppers functions, but what will actually be returned is an existing object, more specifically the instance of the class of which this member function has been called.
Yes, *this is (the value of?) the current object. But the pointer to the current object is this, not &this.
&this, if it was legal, would be a pointer-to-pointer to the current object. But it's illegal, since this (the pointer itself) is a temporary object, and you can't take addresses of those with &.
It would make more sense to ask why we don't do return this;.
The answer is: forming a pointer requires &, but forming a reference doesn't. Compare:
int x = 42;
int *ptr = &x;
int &ref = x;
So, similarly:
int *f1() return {return &x;}
int &f1() return {return x;}
A simple mnemonic you can use is that the * and & operators match the type syntax of the thing you're converting from, not the thing you're converting to:
* converts a foo* to a foo&
& converts a foo& to a foo*
In expressions, there's no meaningful difference between foo and foo&, so I could have said that * converts foo* to foo, but the version above is easier to remember.
C++ inherited its type syntax from C, and C type syntax named types after the expression syntax for using them, not the syntax for creating them. Arrays are written foo x[...] because you use them by accessing an element, and pointers are written foo *x because you use them by dereferencing them. Pointers to arrays are written foo (*x)[...] because you use them by dereferencing them and then accessing an element, while arrays of pointers are written foo *x[...] because you use them by accessing an element and then dereferencing it. People don't like the syntax, but it's consistent.
References were added later, and break the consistency, because there isn't any syntax for using a reference that differs from using the referenced object "directly". As a result, you shouldn't try to make sense of the type syntax for references. It just is.
The reason this is a pointer is also purely historical: this was added to C++ before references were. But since it is a pointer, and you need a reference, you have to use * to get rid of the *.
I know this is silly and the title probably isn't the answer..
I always thought of this as a pointer to the current object which is supplied in every method call from an object (which is not a static method)
but looking at what my code actually returns for example:
Test& Test::func ()
{
// Some processing
return *this;
}
the dereference of this is returned... and the return type is a reference to the object.... so what does that make this? Is there something under the hood I'm not understanding well?
Remember that a reference is simply a different name for an object.
That implies that returning a reference is the same thing as returning an object on type level of abstraction; it is not the same thing in the result: returning a reference means the caller gets a reference to the current object, whereas returning an object gives him (a reference to) a copy of the current object - with all the consequences, like the copy constructor being called, deep copy decisions are being made, etc.
From cppreference:
The keyword this is a prvalue expression whose value is the address of the object, on which the member function is being called.
And then (perhaps easier to grasp):
The type of this in a member function of class X is X* (pointer to X). If the member function is cv-qualified, the type of this is cv X* (pointer to identically cv-qualified X). Since constructors and destructors cannot be cv-qualified, the type of this in them is always X*, even when constructing or destroying a const object.
So, this is not a pointer to a reference, but just a pointer.
Actually you cannot have a pointer to a reference, because taking the address of a reference will give you the address of referenced object.
Further, there is no special syntax in C++ to form a reference. Instead references have to be bound on initialization, for example:
int x = 3;
int& y = x; // x is int, but y is int&
assert( &y == &x); // address of y is the address of x
Similar when returning a reference from a function:
int& get_x() {
static int x = 3;
return x;
}
To put it simply:
test t1; // t1 is a test object.
test& t2 = t1; // t2 is another name for t1.
test* t3; // t3 holds an address of a test object.
*t3; // derefernce t. which gives you, the test object that t3 points to.
this is a pointer to the current test object.
therefore *this is the current test object, and because the return value type is test&, when you call the function, you get the same object you called the function from.
I came across the following piece of code in the book on data structures by Mark Allen Weiss.
template <class Object>
class Cref
{
public:
Cref ( ) : obj ( NULL ) { }
explicit Cref( const Object & x ) : obj ( &x ) {
const Object & get( ) const
{
if ( isNull( ) )
throw NullPointerException( ) ;
else
return *obj;
}
bool isNull( ) const
( return obj == NULL; }
private:
const Object *obj;
};
So the point here is to assign null/initialize a constant reference. But I am not sure I understand the following:
1. We initialize a constant reference with another constant reference x. But why is it again done as obj(&x) ? the & in const Object & x is different from the &x in obj(&x) ? I see this but not very clear why it should be so. Pls explain.
2. The get method() - We try to return a const reference of the private member obj of this class. It is already a const reference. Why return *obj and not just obj ?
3. Why explicit keyword ? What might happen if an implicit type conversion takes place ? Can someone provide a scenario for this ?
Thanks
The member obj is of type Object*, but the constructor takes a reference. Therefore to get a pointer, the address-of operator, &, has to be applied. And the member is a pointer because it can be NULL (set in the default constructor), and references never can be NULL.
The private member is not a const reference, but a poinetr to const. It is dereferenced to get a reference.
In this specific case, I cannot see any negative effect of a potential implicit conversion either.
1) &x in obj(&x) is used as the address-of operator.
2) No, it is a pointer. Its time is Object *, not Object &.
3) To prevent casting from incompatible pointer types which might have their own type-cast operator.
C++ has three flavors of null available:
NULL - obsolete; use it only for checking the return values of C functions which return pointers
0 - deprecated; the literal zero is defined in the Standard to be the null pointer
nullptr - as of C++11, this is the preferred way of testing for null. Furthermore, nullptr_t is a type-safe null.
1) The token & has three meanings:
Unary address-of operator: Take the address of any lvalue expression, giving a pointer to that object.
Reference sigil: In a declaration, means a reference type.
Binary bitwise AND operator - not used here
So it's important to know whether you're looking at a declaration or an expression.
explicit Cref( const Object & x )
Here the sigil appears in the declaration of a function parameter, meaning the type of parameter x is a reference to an Object which is const.
: obj ( &x ) {}
Here the operator is used in a member initializer expression. Member obj is initialized to be a pointer to x.
2) Since member obj is actually a pointer, the dereference operator unary * is needed to get a reference.
3) In general, it's a good idea to use explicit on any (non-copy) constructor which can take exactly one argument. It's just unfortunate that the language doesn't default to explicit and make you use some sort of "implicit" keyword instead when you mean to. In this case, here's one rather bad thing that could happen if the constructor were implicit:
Object create_obj();
void setup_ref(Cref& ref) {
ref = create_obj();
}
No compiler error or warning, but that setup_ref function stores a pointer to a temporary object, which is invalid by the time the function returns!
1) The type of obj is not a reference, obj is a pointer, and a const pointer must be initialized with a address, so, the address-of operator, &, must be applied.
2) The reference the get() method returns is not a reference to the class member obj, but a reference to the object which obj points, so you have to use * to deference it.
3) The keyword explicit means we reject the implicit conversions, that is, we tell the compiler, don't make implicit conversions with this constructor for us.
Example:
class Cref<Object> A;
Object B;
A=B;
It's OK without the explicit--Since we need a Cref object on the right side, the compiler will automate making a Cref object with constructor Cref( const Object & B ). But if you add an explicit, the compiler won't make conversions, there will be a compiling error.
I've got quite a nifty get fnc which returns pointer to 'a type'. Now I would like to reuse this fnc in fnc set to set some value to this type returned by get:
template<class Tag,class Type>
set(Type t, some_value)
{
get<Tag>(t) = value;
}
The only problem I have is that: Because get returns pointer and not reference to a pointer the return type is a rvalue which for most cases is fine but not for this. Is there a way to somehow change the returned value into lvalue?
You can simply use this:
*get<Tag>(t) = value;
The result of dereferencing a pointer is an l-value.
Dereferencing a pointer (with the * operator) yields a reference. The type of the reference depends on the type of the pointer. const T * becomes const T &, while T * becomes T &.
So, if get returns a pointer to a non-const variable, you can write:
*get<Tag>(t) = value;
If get does not meet such requirement, and you can't change it, you'll have to give a set method instead.
I apologize if this has been asked, but how do I create a member function in c++ that returns a pointer in the following scenerios:
1. The returned pointer is constant, but the junk inside can be modified.
2. The junk inside is constant but the returned pointer can be modified.
3. Neither the junk, nor the pointer can be modified.
Is it like so:
int *const func() const
const int* func() const
const int * const func() const
All of the tutorials I've read don't cover this distinction.
Side note:
If my method is declared const then the tutorials say that I'm stating that I won't modify the parameters.. But this is not clear enough for me in the case when a parameter is a pointer. Do my parameters need to be like:
a. void func(const int* const x) const;
b. void func(const int* x) const;
c. void func(const int* const x) const;
I don't know what book you have read, but if you mark a method const it means that this will be of type const MyClass* instead of MyClass*, which in its turn means that you cannot change nonstatic data members that are not declared mutable, nor can you call any non-const methods on this.
Now for the return value.
1 . int * const func () const
The function is constant, and the returned pointer is constant but the 'junk inside' can be modified. However, I see no point in returning a const pointer because the ultimate function call will be an rvalue, and rvalues of non-class type cannot be const, meaning that const will be ignored anyway
2 . const int* func () const
This is a useful thing. The "junk inside" cannot be modified
3 . const int * const func() const
semantically almost the same as 2, due to reasons in 1.
HTH
Some uses of const don't really make much sense.
Suppose you have the following function:
void myFunction (const int value);
The const tells the compiler that value must not change inside the function. This information does not have any value for the caller. It's up to the function itself to decide what to do with the value. For the caller, the following two function definitions behave exactly the same for him:
void myFunction (const int value);
void myFunction (int value);
Because value is passed by value, which means that the function gets a local copy anyway.
On the other hand, if the argument is a reference or a pointer, things become very different.
void myFunction (const MyClass &value);
This tells the caller that value is passed by reference (so behind the screens it's actually a pointer), but the caller promises not to change value.
The same is true for pointers:
void myFunction (const MyClass *value);
We pass a pointer to MyClass (because of performance reasons), but the function promises not to change the value.
If we would write the following:
void myFunction (MyClass * const value);
Then we are back int he first situation. myFunction gets a pointer, which is passed by value, and which is const. Since MyFunction gets a copy of the pointer value, it doesn't matter for the caller whether it is const or not. The most important thing is that myFunction can change the contents of value, because the pointer variable itself is const, but the contents in it isn't.
The same is true for return values:
const double squareRoot(double d);
This doesn't make any sense. squareRoot returns a const double but since this is passed 'by value', and thus needs to be copied to my own local variable, I can do whatever I want with it.
On the other hand:
const Customer *getCustomer(char *name);
Tells me that getCustomer returns me a pointer to a customer, and I am not allowed to change the contents of the customer.
Actually, it would be better to make the char-pointer-contents const as well, since I don't expect the function to change the given string:
const Customer *getCustomer(const char *name);
int *const func() const
You cannot observe the const here except for a few cases
Taking the address of func.
In C++0x, directly calling func with the function-call syntax as a decltype operand, will yield int * const.
This is because you return a pure pointer value, that is to say a pointer value not actually stored in a pointer variable. Such values are not const qualified because they cannot be changed anyway. You cannot say obj.func() = NULL; even if you take away the const. In both cases, the expression obj.func() has
the type int* and is non-modifiable (someone will soon quote the Standard and come up with the term "rvalue").
So in contexts you use the return value you won't be able to figure a difference. Just in cases you refer to the declaration or whole function itself you will notice the difference.
const int* func() const
This is what you usually would do if the body would be something like return &this->intmember;. It does not allow changing the int member by doing *obj.func() = 42;.
const int * const func() const
This is just the combination of the first two :)
Returning a pointer to const makes a lot of sense, but returning a const pointer (you cannot modify) usually adds no value (although some say it can prevent user errors or add compiler optimisation).
That is because the return value belongs to the caller of the function, i.e. it is their own copy so it doesn't really matter if they modify it (to point to something else). The content however does not "belong" to the caller and the implementor of the function may make a contract that it is read-only information.
Const member functions promise not to change the state of the class, although this is not necessarily enforced in reality by the compiler. I am not referring here to const_cast or mutable members so much as the fact that if your class itself contains pointers or references, a const member function turns your pointers into constant pointers but does not make them pointers to const, similarly your references are not turned into references-to-const. If these are components of your class (and such components are often represented by pointers) your functions can change their state.
Mutable members are there for the benefit of allowing your class to change them whilst not changing internal state. These can typically be applied to:
Mutexes that you wish to lock even for reading.
Data that is lazy-loaded, i.e. filled in the first time they are accessed.
Reference-counted objects: You want to increase the reference count if it has another viewer, thus you modify its state just to read it.
const_cast is generally considered a "hack" and is often done when someone else has not written their code properly const-correct. It can have value though in the following situations:
Multiple overloads where one is const and one non-const and the const returns a const-reference and the non-const returns a non-const reference, but otherwise they are the same. Duplicating the code (if it is not a simple data member get) is not a great idea, so implement one in terms of the other and use const_cast to get around the compiler.
Where you want in particular to call the const overload but have a non-const reference. Cast it to const first.
The const method prevents you from modifying the members. In case of pointers, this means you can't reassign the pointer. You can modify the object pointed at by the pointer to your heart's desire.
As the pointer is returned by value (a copy), the caller can't use it to modify the pointer member of the class. Hence adding const to the return value adds nothing.
Things are different if you were to return a reference to the pointer. Now, if the pointer weren't const, this would mean that a function that doesn't have rights to modify a value is granting this right to the caller.
Example:
class X
{
int* p;
public:
int* get_copy_of_pointer() const //the returned value is a copy of this->p
{
*p = 42; //this being const doesn't mean that you can't modify the pointee
//p = 0; //it means you can't modify the pointer's value
return p;
}
int* const& get_reference_to_pointer() const //can't return a reference to non-const pointer
{
return p;
}
};