How pointers are compared in C++?
The last line in the following code shows that values of b and c are different. However, b==c returns true.
#include <iostream>
struct A { int a; };
struct B { int b; };
struct C : A, B { };
int main() {
auto c = new C();
B* b = static_cast<B*>(c);
A* a = static_cast<A*>(c);
a->a = 1;
b->b = 2;
std::cout << c->a << c->b <<"\n";
std::cout << (a==c) << (b==c) << "\n";
std::cout << (long)a << "\n" << (long)b << "\n" << (long)c <<"\n";
}
A sample output that I received using GCC and Clang:
12
11
34073632
34073636
34073632
Don't cast pointers to long, cast them to intptr_t.
std::cout << (intptr_t)a << "\n" << (intptr_t)b << "\n" << (intptr_t)c <<"\n";
Anyhow, see this definition:
struct C : A, B { };
in memory that would look like:
{
A; [sizeof int]
B; [sizeof int]
}
Since A and B are both base classes of C, when you do this:
A* a = static_cast<A*>(c);
You get a pointer to the first 4 bytes of C. When you do this:
B* b = static_cast<B*>(c);
You get a pointer to the last 4 bytes of C, hence the difference. A pointer to type C will always implicitly cast the pointer this way.
Related
I'm working on something which lead me to a situation similar to the example below. I want b to point to a after on test(). Is it possible to this or creating a copy is the only solution?
Thanks.
void test(Object* a, Object* b)
{
std::cout << "test a: " << a << std::endl;
std::cout << "test b: " << b << std::endl;
b = a;
std::cout << "test b assigned: " << b << std::endl;
}
int main()
{
Object* a = new Object();
Object* b = nullptr;
test(a, b);
std::cout << "a: " << a << std::endl;
std::cout << "b: " << b << std::endl;
delete a;
delete b;
}
test a: 0x1aa8930
test b: 0
test b assigned: 0x1aa8930
a: 0x1aa8930
b: 0
In order to modify a pointer, you need to either:
Pass a pointer to your pointer
void test(Object **a, Object **b)
test(&a,&b);
After which you need to dereference that if you want to change the pointer.
Pass a reference to your pointer
void test(Object *&a, Object *&b)
test(a,b);
Here you won't have to dereference anything if you want to change the address.
For a, you don't necessarily have to pass a pointer to pointer or a reference to pointer (unless you plan to modify it too in the future), but for b you have to in order to modify it.
P.S. change your void main() to int main()
You can do like this:
void test(Object* a, Object*& b)
{
std::cout << "test a: " << a << std::endl;
std::cout << "test b: " << b << std::endl;
b = a;
std::cout << "test b assigned: " << b << std::endl;
}
int main()
{
Object* a = new Object();
Object* b = NULL;
test(a, b);
std::cout << "a: " << a << std::endl;
std::cout << "b: " << b << std::endl;
delete a, b;
}
Output will be:
test a: 0x7a0d28
test b: 0
test b assigned: 0x7a0d28
a: 0x7a0d28
b: 0x7a0d28
Its because in question, you have passed the value of b, not a reference to it, which is required to modify it. Variables can only be modified by a function if that function receives the address of those variables, and that can only can be done via either a pointer (Object**) or a reference (Object* &)
Nowadays we have something called shared_ptr, which does exacly what you want. Plus you don't have to clean it up after you're finished with it!
Example:
#include <memory>
#include <iostream>
using Object = int;
void test(const std::shared_ptr<Object>& a, std::shared_ptr<Object>& b)
{
b = a;
std::cout << "test b assigned: " << b.get() << "\n";
}
int main()
{
auto a = std::make_shared<Object>();
std::shared_ptr<Object> b;
std::cout << "test a: " << a.get() << "\n";
std::cout << "test b: " << b.get() << "\n";
test(a, b);
std::cout << "test a: " << a.get() << "\n";
std::cout << "test b: " << b.get() << "\n";
return 0;
}
output (g++ 5.4.0):
test a: 0x21e2c30
test b: 0
test b assigned: 0x21e2c30
test a: 0x21e2c30
test b: 0x21e2c30
live demo
Hi I have the following piece of code -
class A{
public:
A(){
cout << "In A CTR" << endl;
}
virtual void buildTree() = 0;
void print(){
cout << "int A print This = " << this << endl;
}
};
class B{
public:
B(){
cout << "In B CTR" << endl;
}
virtual A* getBuilder() {
cout << " In B getBuilder , this = " << this << endl;
return NULL;
}
virtual void hell(){
cout << "In B hell This =" << this << endl;
}
void print(){
cout << "in B print This = " << this << endl;
}
B* add(B* child){
cout << "In B add , This = " << this <<endl;
}
};
class C : public A, public B{
public:
C(){
cout << "In C CTR" << endl;
}
A* getBuilder() {
cout << "In C getBuilder , this = " << this << endl;
return this;
}
void print(){
cout << "In C print This = " << this << endl;
}
};
class D : public C{
public:
D(){
cout <<"In D CTR" << endl;
}
void buildTree(){
cout << "buildTree in D , This = " << this << endl;
B *b = NULL;
add(b);
}
void print(){
cout << "In D print This = " << this << endl;
}
};
int main() {
B *root = new D();
root->getBuilder()->buildTree();
return 0;
}
I get the following output :
In C getBuilder , this = 0x7f9aa0500100
buildTree in D , this = 0x7f9aa0500100
In B add , this = 0x7f9aa0500108
I am unable to figure out , why the add() in class B is called . Here is my understanding . Please correct me.
root is a pointer of type B and points to D .
So, when root->getBuilder() is called , it calls the virtual function in class C , which returns a pointer of type A* .
So, now root->getBuilder() returns a pointer of type A pointing to D.
Hence root->getBuilder()->buildTree() is able to call buildTree in D .
But in the buildTree in class D , we are calling add which is defined in class B.
How are we able to call this , as the pointer type is A and should not know nothing about B, functions .
Any help is appreciated.
Thanks
This seems to be the question:
But in the buildTree in class D , we are calling add which is defined
in class B. How are we able to call this , as the pointer type is A
and should not know nothing about B, functions.
Calling buildTree on a pointer type of A* where buildTree is marked as virtual is going to call buildTree on a D* given root is of type D. So add is available to D because D can access the public and protected methods of is superclasses.
The original code example is unnecessarily complicated. The same principle can be examined via the following code:
A *root = new D();
root->buildTree();
What you have is basically this (very simplified):
struct B
{
B* add(B*)
{
std::cout << "B::add\n";
}
};
struct C : B
{
// Nothing relevant
};
struct D : C
{
void buildTree()
{
add(NULL);
}
};
int main()
{
D root;
root.buildTree();
}
The class D is a C. The class C is a B. That means D is a B as well. Therefore D has the member function add.
The pointers and indirection are red herrings in the case of how you can call add from a D member function.
I think I see the problem now, and it's about the interface the classes present to the world.
Again with a basic and simplified example:
struct A
{
void funA();
}
struct B
{
// Nothing relevant
};
struct C : A, B
{
// Nothing relevant
};
Then by doing
B* p = new C;
is valid. But even though the pointer p is pointing to an object of C (which is also an A) it does not have the interface of A (or C for that matter), only of B.
If you want to use the functions in A or C you have to use down-casting to cast it to the correct type:
static_cast<D*>(p)->funA(); // Cast to the type `p` *really* is
I wonder how pointers are compared when it comes to multiple inheritance. It seems that in some circumstance, they are equal although the address is obviously different. See the following code:
class A {
int m_i;
};
class B {
double m_d;
};
class C: public A, public B {
char m_c;
};
int main() {
C c;
A *pa = &c;
B *pb = &c;
std::cout << "Address of c is: " << &c << std::endl;
std::cout << "A type pointer to c is: " << pa << std::endl;
std::cout << "B type pointer to c is: " << pb << std::endl;
std::cout << "if pa == &c: " << (pa == &c) << std::endl;
std::cout << "if pb == &c: " << (pb == &c) << std::endl;
return 0;
}
The output is:
Address of c is: 00F6F870
A type pointer to c is: 00F6F870
B type pointer to c is: 00F6F878
if pa == &c: 1
if pb == &c: 1
There is no wonder pb is different from &c. The weird thing is (pb == &c) delivers 1. I am now confused how (pb == &c) is actually evaluated.
You can only compare values that have the same type. Note, I'm ignoring the case of an overloaded operator== for the purpose of this answer.
Here, you're comparing two pointers to different classes. At this point, the compiler tries to figure out if it's possible to convert one of the pointers to the type of the other pointer.
A pointer to a subclass can be automatically converted to a pointer to its superclass. And this is what the compiler does. The end result is the same actual pointer value, and they compare equal.
This line:
std::cout << "if pb == &c: " << (pb == &c) << std::endl;
in order to compare &c with pb it has to perform a conversion so that the types of the two values match. We already know that (B*)&c results in the value that is in pb, so what actually happens here is quite simply
std::cout << "if pb == &c: " << (pb == (B*)&c) << std::endl;
which results in comparing equal values.
class X {
char m_x;
};
class A {
int m_i;
};
class B {
double m_d;
};
class C: public X, public A, public B {
char m_c;
};
int main() {
C c;
A *pa = &c;
B *pb = &c;
void *va = pa;
void *vb = pb;
std::cout << "Address of c is: " << &c << std::endl;
std::cout << "A type pointer to c is: " << pa << std::endl;
std::cout << "B type pointer to c is: " << pb << std::endl;
std::cout << "void type pointer equal to pA is: " << va << std::endl;
std::cout << "void type pointer equal to pB is: " << vb << std::endl;
std::cout << "if pa == &c: " << (pa == &c) << std::endl;
std::cout << "if pb == &c: " << (pb == &c) << std::endl;
std::cout << "if va == &c: " << (&c == va) << std::endl;
std::cout << "if vb == &c: " << (&c == vb) << std::endl;
return 0;
}
yields the following result:
Address of c is: 0x75270a47f5f0
A type pointer to c is: 0x75270a47f5f4
B type pointer to c is: 0x75270a47f5f8
void type pointer equal to pA is: 0x75270a47f5f4
void type pointer equal to pB is: 0x75270a47f5f8
if pa == &c: 1
if pb == &c: 1
if va == &c: 0
if vb == &c: 0
The compiler converts the &c address by casting it to the same type as the pointer you compared it to. To make the point clear I displaced Class A using another class, when I then copy the addresses to void* pointers it becomes clear that the actual 'value' stored is not equal to the 'value' stored in &c.
After reading C++: Comparing pointers of base and derived classes, I thought for sure this wouldn't work.
When I executed this, the printed addresses for c_as_b and &c were different, so why does this print "seems safe to compare pointers in same hierarchy"? What is being compared besides the printed addresses that could result in true?
Can you give a similar small example where the == results in false?
#include <iostream>
using namespace std;
struct A { std::string s; };
struct B { int i; };
struct C : A, B { double d; };
int main() {
C c;
B* c_as_b = &c;
A* c_as_a = &c;
cout << "c_as_a: " << c_as_a << endl
<< "c_as_b: " << c_as_b << endl
<< "&c: " << &c << endl;
cout << (c_as_b == &c ? "seems safe to compare pointers in same hierarchy" : "definately not safe") << endl;
return 0;
}
Sample output:
c_as_a: 0xbfb98f10
c_as_b: 0xbfb98f14
&c: 0xbfb98f10
seems safe to compare pointers in same hierarchy
The pointer equality comparison c_as_b == &c will do an implicit pointer conversion. From [expr.eq]:
If at least one of the operands is a pointer, pointer conversions (4.10), function pointer conversions (4.12),
and qualification conversions (4.4) are performed on both operands to bring them to their composite pointer
type (Clause 5).
Basically, &c will be converted to a B* so that the comparison can happen. At which point, it is exactly the same as c_as_b (since that's how you got that pointer to begin with), so they compare equal.
In this example, c is statically upcast to B, and then compared with c_as_b yielding true.
To answer the part of the question that nobody touched on: Can you give a similar small example where the == results in false?
Here is a similar example where the == results in false, using dynamic_cast<void*> makes the same comparison true, and commented out is a way that == results in a compile time error:
#include <iostream>
using namespace std;
struct A { virtual ~A() {} };
struct B : A { };
struct C : A { };
struct D : B, C { };
int main() {
D d;
C* c = &d;
B* b = &d;
A* a_through_b = b; // &d results in error: 'A' is an ambiguous base of 'D'
A* a_through_c = c;
cout << "&d: " << &d << endl
<< "c : " << c << endl
<< "b : " << b << endl
<< "a_through_b : " << a_through_b << endl
<< "a_through_c : " << a_through_c << endl;
cout << (a_through_b == a_through_c ? "a_through_b == a_through_c" : "a_through_b != a_through_c") << endl;
cout << (dynamic_cast<void*>(a_through_b) == dynamic_cast<void*>(a_through_c) ? "dynamic_cast<void*>(a_through_b) == dynamic_cast<void*>(a_through_c)" : "dynamic_cast<void*>(a_through_b) != dynamic_cast<void*>(a_through_c)") << endl;
//cout << (a_through_c == &d) << endl; // error: 'A' is an ambiguous base of 'D'
cout << (dynamic_cast<void*>(a_through_c) == dynamic_cast<void*>(&d) ? "dynamic_cast<void*>(a_through_c) == dynamic_cast<void*>(&d)" : "dynamic_cast<void*>(a_through_c) != dynamic_cast<void*>(&d)") << endl;
return 0;
}
Sample output:
&d: 0xbff6d558
c : 0xbff6d55c
b : 0xbff6d558
a_through_b : 0xbff6d558
a_through_c : 0xbff6d55c
a_through_b != a_through_c
dynamic_cast<void*>(a_through_b) == dynamic_cast<void*>(a_through_c)
dynamic_cast<void*>(a_through_c) == dynamic_cast<void*>(&d)
In the following code, I am having trouble figuring out how to make b point to c so that if you change the value pointed to by b, c is changed (but not a). I tried int *b = &c;. So my question ultimately is: How do you point to a value that is pointing to another, without changing the value of the former?
#include <iostream>
int main(){
int a = 8;
int c = 12;
//std::cout<< a<< std::endl;
std::cout << &a << std::endl;
int *b = &a;
std::cout << *b << std::endl;
std::cout << b << std::endl;
std::cout << b+1 << std::endl;
a = 6;
std::cout << *b << std::endl;
b = &c; // just edited this now it works.
//std::cout << c << std::endl;
system("pause");
return 0;
}
Just take the address of c and assign it to b:
b = &c;
Now if you dereference b, with *b, you get the object denoted by c. If you modify this object in anyway, it will not affect the value of a.