c++ return *this, how to think it - c++

When I searched for return *this, I found someone explaining it as a chained assignment function.
But when I follow the blogger's implementation, I found that this is not the case.
Though one has the code return *this, the other has not, the two results is same.
#include <iostream>
using namespace std;
class Wd {
private:
public:
int a;
int b;
Wd &operator=(Wd const &as) {
this->a = as.a;
this->b = as.b;
return *this;
};
};
int main() {
Wd a;
a.b =3;
a.a =4;
Wd c,b,d;
d.a=6;
d=c=b=a;
cout<<d.a<<a.a<<b.a<<c.a<<endl;
return 0;
}

Semantic of assignment expression like a=b is :
first, set the value of a to the value of b,
second, the value of the whole expression is the value of a after assignment. a=b=c is equivalent to a = (b=c).
As a=b is a.operator=(b), the return value of the operator must be the value of a after assignment, thus the following is the most common way of implementing it:
K &operator=(const K &arg) {
// code to assign this with values in arg
return *this; // return the current assigned object
}

So this
class Wd{
public:
int a;
int b;
Wd &operator =(Wd const &as){
this->a = as.a;
this->b = as.b;
return *this;
};
};
creates an object with only one function operator=.
That function is defined as returning a reference to the invoking object.
return *this;
says 'return what the this object points at'. this points at the current Wd instance. If the retrun type we Wd then it would retunr a copy, but becuase the return type is Wd& it returns a reference to it, this is effectively a pointer
so now look at the main code
Wd a;
a.b =3;
a.a =4;
first we create a Wd and initialize its members.
Then we do (simplified a bit)
Wd c;
Wd d;
d = c = a;
d = c= a translates to
d.operator=(c.operator=(a))
and because c.operator=(a) returns a reference to a this is equivalent to
d.operator=(a)
One of the main reason for the existance of references is to permit chaining like this. The most well known one is this
cout << x << " " << y << "!!" << z;
this works because operator<< for streams is defined as returning a reference to its invoking stream.

Related

Why don't reference members refer the assigned variable on nested vectors? What's a proper way to declare an alternative way to access a class member?

I would like to declare an alternative way to access a class member (an array position specifically), as in
class Foo {
int a[2];
int &a_first = a[0];
};
such that any access to a_first in a Foo instance is for all purposes equivalent to accessing a[0] of that same instance.
The code above works as I expected with singular instances and single vectors of the class, but when used on a nested vector the reference address differs from the member address:
#include <iostream>
#include <vector>
class A {
public:
int m;
int &mref = m;
};
int main()
{
A a;
std::cout << (&a.m == &a.mref) << '\n'; // output: 1
std::vector<A> av1(1);
std::cout << (&av1[0].m == &av1[0].mref) << '\n'; // output: 1
std::vector<std::vector<A>> av2(1, std::vector<A>(1));
std::cout << (&av2[0][0].m == &av2[0][0].mref) << '\n'; // output: 0
return 0;
}
I thought reference variables acted as aliases of their assigned variable and were resolved at compile time without being assigned any actual memory at runtime, unlike pointers. Why is this not consistent with the behavior displayed above? What would be a correct way to achieve the alias I want?
The code above works as I expected
Actually it doesn't:
class A {
public:
int m{};
int &mref = m;
};
int main()
{
A a;
A a2 = a;
std::cout << (&a2.m == &a2.mref) << '\n'; // output: 0
};
A reference can be bound only on initialization. Copying will copy the value, not re-bind the reference. So any copy of an object of type A will mess up your reference. This is what happens in your nested vector example. You don't need a nested vector to see this. Try and push in a vector<A>, the vector will have to resize and during the resize will copy its elements, messing your reference.
I thought reference variables acted as aliases of their assigned variable ...
True
... and were resolved at compile time without being assigned any actual memory at runtime, unlike pointers.
Not always. You cannot always resolve at compile time the reference, in which case the reference will actually be implemented with a pointer behind the scenes.
Possible solutions:
use std::reference_wrapper, the copy assignment operator rebinds the reference, but you will need to implement custom copy constructor/assignments for your class:
class A {
public:
int m{};
std::reference_wrapper<int> mref = m;
A() = default;
A(const A& other) noexcept
: m{other.m},
mref{m}
{}
A& operator=(const A& other) noexcept
{
m = other.m;
mref = m;
return *this;
}
};
use a method that returns a reference to the variable
class A {
public:
int m{};
int& mref() { return m; }
const int& mref() const { return m; }
};

dynamic_cast of a reference to copied object fails

I have a function getA() which returns a const reference of base type A, since it's const, it cannot dynamic_cast it, so I make a copy of the const reference and then created a reference to the copied object, but when I call dynamic_cast to the reference of the copied object, it fails, the code is shown below:
struct A {
int c = -1;
virtual ~A() {}
};
struct B : A {int aa = 0;};
const A& getA(){
std::unique_ptr<A> ap(new B);
return *ap;
}
int main()
{
const A& a = getA();
A acopy = a;
acopy.c = -2;
A& acopyr = acopy;
std::cout << a.c << std::endl;
try{
B& b = dynamic_cast<B&>(acopyr);
std::cout << b.aa << std::endl;
}catch(std::bad_cast b){
std::cout << "bad" << std::endl;
}
}
The output is
-1
bad
acopy is an object of dynamic (and static) type A. Notice how it was declared: an object of type A. So of course it cannot be cast to a B&.
From your description, I take it you just want to dynamically cast getA() to a const reference to B. There's nothing stopping you from that:
const B& b = dynamic_cast<const B&>(getA());
Side note: I assume the getA implementation in your question is just for demonstration purposes, but it's very wrong. As soon as ap goes out of scope (that is, as soon as getA returns), it will destroy the object to which it points, so you're returning a dangling reference and thus invoking Undefined Behaviour.

making public member read only

class A{
private:
int a;
public:
const int &ref = a;
};
int main() {
A obj;
obj.a = 20; // error cause private
obj.ref = 30; // not private but const so ERROR
return 0;
}
I'm trying to make a member variable accessible but read only through the interface. Currently I've tried this approach and it seems to compile fine. I made a const reference to my original variable int a and made it public. Is there anything that's wrong with this practice that I might be missing out? Or is this example safe and sound to use for practical purposes?
Nothing wrong with providing a member function with const correctness applied (and I've used that too and intend to do so always), but I'm asking is there any thing wrong with this way if I have to provide a variable that is only read-only.
Thankyou :)
class A{
private:
int a;
public:
const int &ref = a;
};
is there any thing wrong with this way if I have to provide a variable that is only read-only
There are at least a couple drawbacks with this design decision for class A.
1: Class Size
Also as Dieter Lücking mentions in a
comment:
increasing the size of the class, needlessly
2: Copy Semantics
It breaks the compiler generated copy assignment operator. For example, the following code behavior is generally desirable but doesn't work.
A obj1;
// ...
A obj2;
// make changes to 'obj2'
// Update 'obj1' with the changes from 'obj2'
obj1 = obj2; // This copy doesn't work!
More information:
Should I prefer pointers or references in member data?
Assignment operator with reference class member
Thinking in C++, 2nd ed. Volume 1 ©2000 by Bruce Eckel, 11: References & the Copy-Constructor
There are certain rules when using references:
A reference must be initialized when it is created. (Pointers can be initialized at any time.)
Once a reference is initialized to an object, it cannot be changed to refer to another object. (Pointers can be pointed to another object at any time.)
You cannot have NULL references. You must always be able to assume that a reference is connected to a legitimate piece of storage.
It may be possible to implement a custom assignment operator but that's more code to maintain (i.e., another drawback in my opinion).
#include <iostream>
class A
{
private:
int a;
public:
explicit A(int value) : a(value) {}
A& operator=(const A& other)
{
a = other.a;
return *this;
}
const int& ref = a;
};
int main()
{
A obj1(10);
std::cout << "1: " << obj1.ref << "\n";
A obj2(20);
std::cout << "2: " << obj2.ref << "\n";
obj1 = obj2;
std::cout << "1: " << obj1.ref << "\n";
return 0;
}
The idiomatic way to address this issue is to use a proper accessor function.
class A {
private:
int a;
public:
int getA() const { return a; }
};
The standard way to do this in C++ is by making the actual member private but including a public 'getter' method for the interface, as below:
class A{
private:
int a;
public:
int get_a() const { return a; }
A() : a(20) {}
};
int main() {
A obj;
int n = obj.get_a(); // n = 20
return 0;
}
The user cannot set the value of A::a but can use A::get_a to retrieve its value.

How class constructor works in C++

I saw an online C++ test regarding the constructor. I can figure out most of the answers but am puzzled by some in the following. Hope someone can help me out.
Here's the example.
#include <iostream>
class A {
public:
A(int n = 0) : m_n(n) {
std::cout << 'd';
}
A(const A& a) : m_n(a.m_n) {
std::cout << 'c';
}
private:
int m_n;
};
void f(const A &a1, const A &a2 = A())
{
}
int main() {
A a(2), b;
const A c(a), &d = c, e = b;
b = d;
A *p = new A(c), *q = &a;
static_cast<void>(q);
delete p;
f(3);
std::cout << std::endl;
return 0;
}
What I don't really get is why "&d = c" doesn't output anything. Also adding another overloading constructor like A(const A *a) : m_n(a->m_n) { std::cout << 'b'; } doesn't output anything either for *q = &a. So what can I do to make it work?
Many thanks for any advice. I am very curious about this.
There's no output for these because d and q are not of type A, i.e. they are not A objects. d is a reference to A and q is a pointer to A. Initialising a reference and initialising or assigning a pointer does not manipulate the referred-to/pointed-to A object at all, hence no output.
To address your question - there is nothing to "make work," it works just as it should.
That to be more clear I will rewrite this statement
const A c(a), &d = c, e = b;
as
const A c(a);
const A &d = c;
Here d is declared as a reference to an object of type A. It does not create a new object. It refers to an object that is already created. In this case d referes to c. In fact d is simply an alias for object c.
This code snippet
A *p = new A(c), *q = &a;
also can be rewritten for simplicity
A *q = &a;
In this statement pointer q is simply assigned by the address of a. Neither object is created. Simply q now points to already created early object a.
&d = c doesn't output anything because you're not calling the constructor.
If we expand that code fragment a bit...
A &d = c
What your code is saying there is "declare d to be a reference to an object of type A, which points to c". Because you're creating a reference, you're not calling the constructor, c and d are the same object.
The same applies to q, but instead of creating a reference, you're creating a pointer and assigning it the address of an existing instance of type A. The constructor isn't called because you're not creating a separate object, you're linking to an existing one.

Pointer Wrapper: dereference operator

I'm pretty new to C++ and as an exercise (and perhaps eventually .Net utility) I'm doing a pointer wrapper (actually in C++/CLI, but this applies to C++ as well). This pointer wrapper (called Apont) currently behaves just like a pointer would, as the test below can show, if lines marked 1. and 2. are commented out:
int main(array<System::String ^> ^args)
{
double ia = 10; double ip = 10;
double *p = &ip; // pointer analogy
Apont<double> ^a =
gcnew Apont<double>(ia); // equivalent to what's below, without errors
a = ~ia;/* 1. IntelliSense: expression must have integral or unscoped enum type
error C2440: '=' : cannot convert from 'double' to 'Utilidades::ComNativos::Apont<T> ^'
error C2171: '~' : illegal on operands of type 'double'*/
Console::WriteLine("ip = {0}; *p = {1}; ia = {2}; !a = {3}", ip, *p, ia, !a);
ia = 20; ip = 20;
Console::WriteLine("ip = {0}; *p = {1}; ia = {2}; !a = {3}", ip, *p, ia, !a);
*p = 30; // pointer analogy
a->Valor = 30; // does exacly what's below, without errors
!a = 30;/* 2. IntelliSense: expression must be a modifiable lvalue
error C2106: '=' : left operand must be l-value */
Console::WriteLine("ip = {0}; *p = {1}; ia = {2}; !a = {3}", ip, *p, ia, !a);
//a->Dispose();
Console::ReadKey();
p = nullptr;
return 0;
}
There are two things I don't like here, marked with 1. and 2. in the code comments, before the lines with errors. The operator~ (see 1.) is defined outside Apont, below:
template<typename T> static Apont<T>^% operator ~(T& valor)
{
return gcnew Apont<T>(valor);
}
I think this one has to be defined outside Apont, but I'm not sure. I cannot understand very well the errors it produces (these are, of course, in the use, not in the definition).
To set the value to which the instance of Apont refers I must use a property (the line marked 2. doesn't work, with errors in the setting usage only), Apont::Valor, which is the equivalent to use *p. What I'd like to do is as I use *p to get or set the value it points to, use !a with the same effect on Apont. Here's Apont::operator!()'s current definition:
T operator !()
{
return Valor;
}
As you can see in 2. (comment in the code, before the respective errors), it doesn't work for setting a value. Maybe I should return a reference? Make another operator with the same name, perhaps outside the class? I tried several options, however, I got similar errors, and came out more confused.
The question is: how can I make an operator that behaves like & (in this case, ~) and one that behaves like * (in this case, !, for dereference, but that behaves like Apont::Valor, whose old definition you can see below)?
property T Valor
{
T get()
{
if (pointer != nullptr)
return *pointer;
else if (eliminado && ErroSeEliminado) // means "disposed && ErrorIfDisposed"
throw gcnew ObjectDisposedException("O objeto já foi pelo menos parcialmente eliminadao.");
else if (ErroSeNulo) // means "ErrorIfNull"
throw gcnew NullReferenceException();
else
return 0;
// don't worry, this is not default behavior, it is returned only if you want to ignore all errors and if the pointer is null
}
void set(T valor)
{
*pointer = valor;
}
}
Let me recap in a new answer for clarity.
Solving the ! operator is easy, as I said in my previous answer, just add a reference.
So for the operator ~, the goal was to have it behave like the & operator and call the constructor of the pointer wrapper class.
I don't think that is possible. It is certainly possible for user defined objects, but I don't think it is possible to overload unary operators for builtin types. So there are three solutions depending on what you prefer:
The first one does exactly what you want, but will break for primitive types:
#include <iostream>
template<typename T>
struct A {
T* payload;
A()
: payload(NULL){}
A(T *ptr)
: payload(ptr) {}
T& operator !(){
return *payload;
}
};
// this will not work for primary types
template<typename T>
A<T> operator ~(T &b){
return A<T>(&b);
}
struct B{
int test;
};
int main(){
B b; b.test = 4;
A<B> a;
a = ~b; // I think this is what you want
std::cerr << (!a).test << std::endl;
// this does not work
//int i = 4;
//A<int> a;
//a = ~i;
}
Second solution: use a compound assignment operator. Pros are the side effects are minimal, cons is this is not very intuitive and might break the nice design you had in mind.
#include <iostream>
template<typename T>
struct A {
T* payload;
A() : payload(NULL){}
T& operator !(){
return *payload;
}
};
template<typename T>
A<T>& operator &=(A<T> &a, T& b){ // should be friend of the above
a.payload = &b;
return a;
}
int main(){
int i = 3;
A<int> a;
a &= i;
std::cerr << !a << std::endl;
}
Third solution: overload the basic assignment operator. This is more intuitive to write but has a lot of side effects:
#include <iostream>
template<typename T>
struct A {
T* payload;
A() : payload(NULL){}
T& operator !(){
return *payload;
}
A<T>& operator = (T & b) {
payload = &b;
return *this;
}
};
int main(){
int i = 3;
A<int> a;
a = i;
std::cerr << !a << std::endl;
}
Someone might have a solution to hijack the operators for primitive types, but i can't think of any simple solution.
If i understood your code correctly, you want the operator ~ to return a copy of the pointer wrapper and the operator ! to act as dereference?
In this case, you can define the unary operator ~ inside the Apont class which calls a copy constructor. And the operator ! has to return a reference indeed if you want to asign a value.
I think the following c++ code defines what you want to do (I renamed Apont to A):
#include <iostream>
template<typename T>
struct A {
T* payload;
A(T *ptr)
:payload(ptr) {}
A(const A&other)
:payload(other.payload) {}
T& operator !(){
return *payload;
}
T* operator ~(){
return payload;
}
};
int main(){
#define PRINT(X) std::cerr << #X << " = " << X << std::endl
int i = 0;
PRINT(i);
A<int> a(&i);
!a = 1;
PRINT(i);
A<int> b = ~a;
!b = 2;
PRINT(i);
}
The output of the code above is:
i = 0
i = 1
i = 2
According to your comments, you said you wanted the operator ! to behave exactly like the wrapped pointer. You can do so, but then the syntax changes and you need to dereference it to assign a new value (because it is a pointer...). ie something like:
#include <iostream>
template<typename T>
struct A {
T* payload;
A(T *ptr): payload(ptr) {}
// this now behaves like accessing the wrapped pointer directly
T*& operator !(){
return payload;
}
};
int main(){
#define PRINT(X) std::cerr << #X << " = " << X << std::endl
int i = 0;
int j = 999;
PRINT(i);
A<int> a(&i);
*(!a) = 1; // note the change of syntax here
PRINT(*!a); // and here
!a = &j; // but now you can change the wrapped pointer through the operator
PRINT(*!a);
}