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.
Related
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.
why I can call non const method from ref member inside const method?
I am expected to get compile error like in case if m_a were not reference type.
run on http://cpp.sh/
// Example program
#include <iostream>
class A
{
public:
void nonConstMethodOfA()
{
std::cout << "nonConstMethodOfA is called" << "!\n";
}
};
class B
{
public:
B(A& a)
: m_a(a)
{
constMethodOfB();
}
private:
A& m_a;
void constMethodOfB() const
{
m_a.nonConstMethodOfA();
}
};
int main()
{
A varA;
B varB(varA);
}
const A & means "a reference to a const A"
A & means "a reference to a mutable A"
A reference cannot be reassigned, so A & also implicitly means "a const reference to a mutable A".
Const member function means your this will point to a const object, thus this->fn() can only be called if fn() is const. It doesn't lock the type, nor any similar-typed input parameters or globals. You can, however, specify those as const as well if you wish.
If a function takes a const & argument it should be immutable.
Why can I change values in a class passed as const?
How can I prevent a function taking const & to change values?
Note: compiles on vs2012 ad g++ 4.8.2
#include "iostream"
class Foo {
public:
Foo() : a(-99) {}
int a;
};
class Bar{
public:
Bar (Foo& f): rFoo(f), pFoo(&f), foo(f) {}
Foo& rFoo;
Foo* pFoo;
Foo foo;
};
void setA (const Bar & b){
Foo* f = new Foo();
Foo f2 = *f;
f->a = 7;
//b.foo.a = 8; // error C3490: 'a' cannot be modified because it is being accessed through a const object
//b.pFoo = f; // error C3490: 'pFoo' cannot be modified because it is being accessed through a const object
b.pFoo->a = 9; // OK... the pointer is const the location its pointing to not...
b.rFoo.a = 10; // Maybe ... the reference may be const, the location its is referencing not ...
b.rFoo = *f; // Why can I modify the reference ?
}
int main(int argc, char* argv[]){
Foo f;
Bar b(f);
std::cout << "one: " << b.rFoo.a << std::endl;
b.pFoo->a = 1;
b.foo.a = 2;
std::cout << "two: " << b.rFoo.a << std::endl;
setA(b);
std::cout << "three: " << b.rFoo.a << std::endl;
return 0;
}
Many Thanks in advance
You can modify the reference for the same reason you can modify the pointed to object by pFoo. Since you aren't modifying the objects member, but another referenced object.
b.rFoo = *f; // Foo's assignment operator invoked
That's why you should not expose members variables. Since you can't enforce a prevention to modify referenced objects, other than in your own member functions.
b.rFoo = *f
is not changing rFoo itself, it is equivalent to
b.rFoo.operator=(*f);
which copies *f to the object referenced by rFoo.
The const qualifier of an object indicates that the abstract state of this object won't change (i.e., from the client's point of view). This is not exactly the same as saying that the object's raw bits are not going to change.
It is forbitten to C++ compilers to consider objects as raw bits, unless they can resolve the problem of aliasing. which in your case the compiler cannot. This is due to the fact that Foo* pFoo is a pointer to an object and consequently the state of this object is modifiable. That is, even if the object that pFoo points to changes, the object that contains pFoo (i.e., b) doesn't change since pFoo continues to point to the same object.
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.
Consider the sample code below:
class A
{
public:
A() : n(0) {}
int n;
};
class B
{
public:
B(A* a) : mA(a) { }
B(const A* a) : mConstA(a) { }
union {
A* mA;
const A* mConstA;
};
};
int main()
{
A a;
B b1(&a);
B b2(const_cast<const A*>(&a));
return 0;
}
At construction, b1 would have a mutable pointer to a, while b2 would have an immutable pointer to a. In this scenario, b1.mA equals b2.mConstA, and b1.mConstA equals b2.mA.
Are these equalities always true when you have a union of const and non-const object pointers?
Similarly, the code below compiles/runs fine:
int main()
{
const A a;
B b(&a);
b.mA->n = 3; // Blasphemy!!!
return 0;
}
But is it guaranteed for b.mA to always be equal to b.mConstA?
Are these equalities always true when you have a union of const and non-const members?
Yes, both pointers will refer to the same object in the same address. The bits in memory will be the same.
But is it guaranteed for b.mA to always be equal to b.mConstA?
Yes, their values will be the same, but that does not mean that you can really use it. This is equivalent to using const_cast, you will get a non-const pointer to the object, but if the object is really const, using that pointer to modify the object is undefined behavior.