Regarding the following C++ program:
class Base { };
class Child : public Base { };
int main()
{
// Normal: using child as base is allowed
Child *c = new Child();
Base *b = c;
// Double pointers: apparently can't use Child** as Base**
Child **cc = &c;
Base **bb = cc;
return 0;
}
GCC produces the following error on the last assignment statement:
error: invalid conversion from ‘Child**’ to ‘Base**’
My question is in two parts:
Why is there no implicit conversion from Child** to Base**?
I can make this example work with a C-style cast or a reinterpret_cast. Using these casts means throwing away all type safety. Is there anything I can add to the class definitions to make these pointers cast implicitly, or at least phrase the conversion in a way that allows me to use static_cast instead?
If this was allowed, you could write this:
*bb = new Base;
And c would end up pointing to an instance of Base. Bad.
Pointers are virtual address. Normally you are responsible for what you do with it. Using msvc 2019. I can cast one to base, but not two:
example 1:
int p;
int *p1 = &p;
int **p2 = &p1; //OK
example 2:
struct xx {};
struct yy : public xx {};
yy p;
yy *p1 = &p;
xx **p2 = &p1; //Just a strange error
example 3:
struct xx {};
struct yy : public xx {};
yy p;
xx *p1 = &p;
xx **p2 = &p1; //OK
Related
Sometimes, e.g. when interfacing C++ and C code, it can make sense to cast a pointer to a C++ object to void * and back. The following should be well defined for any C++ class A:
// (1)
A *a = new A(...);
void *a_void = static_cast<void *>(a);
a = static_cast<A *>(a_void);
But what if instead of casting a to void * I cast it to some other type, in particular a declared but not defined record type?
// (2)
struct foo;
A *a = new A(...);
foo *a_foo = reinterpret_cast<foo *>(a);
a = reinterpret_cast<A *>(a_foo);
And if that is well-defined, what about doing it in a "roundabout" way like so:
// (3)
struct foo;
struct bar;
A *a = new A(...);
foo *a_foo = reinterpret_cast<foo *>(a);
bar *a_bar = reinterpret_cast<bar *>(a_foo);
a = reinterpret_cast<A *>(a_bar);
My intuition is that (1) and (2) are well-defined but (3) is not because technically it's missing a reinterpret_cast from a_bar * to a_foo *. Is that correct?
#include <iostream>
using namespace std;
class A
{
public:
A(int x){ a = x;}
~A();
private:
int a;
};
int main()
{
A* a = new A(10);
void** p;
p = &a;
return 0;
}
After compiling with g++ (GCC) 4.1.2 20080704 , I am getting following error :
test.cpp: In function 'int main()':
test.cpp:17: error: invalid conversion from 'A**' to 'void**'
There's one star to much. void* can already hold any pointer, without casts:
int main()
{
A* a = new A(10);
void* p;
p = &a;
return 0;
}
This works for multiple levels, even:
int main()
{
A* a = new A(10);
A** aa = &a;
A*** aaa = &aa;
void* p = &aaa;
}
This works because A*** is a pointer to a A**.
You need to use reinterpret_cast:
It is purely a compiler directive which instructs the compiler to treat the sequence of bits (object representation) of expression as if it had the type new_type.
In this case your expression will be &a which has the type A** and your new_type will have the type void**:
p = reinterpret_cast<void**>(&a);
Do have a care here as C++ isn't really that fond of the void type and your code is very likely going to violate Type Aliasing Rules.
In my mind a cast to void** is an indication that a template should probably be used. Without seeing your code I can't guarantee that, but, if you want to fill me in anymore in the comments perhaps I can help.
You can't just assign the value of one type (A**) to the variable of another one (void**), if it can't be converted implicitly. You need to explicitly convert value from one type to another:
class A
{
public:
A(int x){ a = x;}
~A();
private:
int a;
};
int main()
{
A* a = new A(10);
void** p;
// use `reinterpret_cast'
p = reinterpret_cast<void**>(&a);
// C-style cast works but it is a bad practice in C++
p = (void**)&a;
return 0;
}
#include <iostream>
class A
{
public:
A() : m_i(0) { }
protected:
int m_i;
};
class B
{
public:
B() : m_d(0.0) { }
protected:
double m_d;
};
class C
: public A
, public B
{
public:
C() : m_c('a') { }
private:
char m_c;
};
int main()
{
C c;
A *pa = &c;
B *pb = &c;
const int x = (pa == &c) ? 1 : 2;
const int y = (pb == &c) ? 3 : 4;
const int z = (reinterpret_cast<char*>(pa) == reinterpret_cast<char*>(pb)) ? 5 : 6;
std::cout << x << y << z << std::endl;
return 0;
}
This code prints out 136 which would suggest that the first equality was true, second also but not the third. Since pa and pb are both set to &c the first two would make sense but then why would the third equality be false?
I ran this code in Visual C++ 2012 and used debugger to check the addresses:
pa == 0x003bfc90
pb == 0x003bfc98
&c == 0x003bfc90
Apparently, pa and pb don't point to the same address which would mean that the third equality should be false (and it is). But then why are the first two true? Could you explain to me what is going on here?
The two pointers do indeed have different values since they point to different sub-objects of c; these two objects must exist at different locations.
Without reinterpret_cast, the equality comparison first looks for a suitable conversion to the same pointer type. This converts &c from C* to B* by modifying the pointer value to point to the B sub-object of c - exactly the same conversion that was applied when initialising pb. After that conversion, both pointers have the same value, and so compare equal.
reinterpret_cast means that the pointer should be converted to the target type without modifying its value, whether or not that conversion is meaningful. So, after that conversion, the pointers still have different values, and compare not equal.
Regarding the following C++ program:
class Base { };
class Child : public Base { };
int main()
{
// Normal: using child as base is allowed
Child *c = new Child();
Base *b = c;
// Double pointers: apparently can't use Child** as Base**
Child **cc = &c;
Base **bb = cc;
return 0;
}
GCC produces the following error on the last assignment statement:
error: invalid conversion from ‘Child**’ to ‘Base**’
My question is in two parts:
Why is there no implicit conversion from Child** to Base**?
I can make this example work with a C-style cast or a reinterpret_cast. Using these casts means throwing away all type safety. Is there anything I can add to the class definitions to make these pointers cast implicitly, or at least phrase the conversion in a way that allows me to use static_cast instead?
If this was allowed, you could write this:
*bb = new Base;
And c would end up pointing to an instance of Base. Bad.
Pointers are virtual address. Normally you are responsible for what you do with it. Using msvc 2019. I can cast one to base, but not two:
example 1:
int p;
int *p1 = &p;
int **p2 = &p1; //OK
example 2:
struct xx {};
struct yy : public xx {};
yy p;
yy *p1 = &p;
xx **p2 = &p1; //Just a strange error
example 3:
struct xx {};
struct yy : public xx {};
yy p;
xx *p1 = &p;
xx **p2 = &p1; //OK
how can I convert any object of my own class convert into pointer to void?
MyClass obj;
(void*)obj; // Fail
MyClass obj;
void *p;
p = (void*)&obj; // Explicit cast.
// or:
p = &obj; // Implicit cast, as every pointer is compatible with void *
But beware ! obj is allocated on the stack this way, as soon as you leave the function the pointer becomes invalid.
Edit: Updated to show that in this case an explicit cast is not necessary since every pointer is compatible with a void pointer.
You cant convert a non-pointer to void*. You need to convert the pointer to your object to void*
(void*)(&obj); //no need to cast explicitly.
that conversion is implicit
void* p = &obj; //OK
If you use the address, you can convert it to a void pointer.
MyClass obj;
void *ptr = (void*)&obj; // Success!
To do something which has any chance of being meaningful, first you have to take the address of an object, obtaining a pointer value; then cast the pointer.
MyClass obj;
MyClass * pObj = &obj;
void * pVoidObj = (void*)pObj;
i beleive you could only convert a pointer to an object to a pointer to void ???
Perhaps: (void*)(&obj)
In addition to the technical answers: Assert, that you avoid multiple inheritance or else you don't assign the address of super-class interfaces to a void*, for they will not be unique! E.g.
class S1 { int u; };
class S2 { int v; };
class MyClass : public S1, public S2 {};
MyClass obj;
S2* s2 = &obj;
void * p1 = &obj;
void * p2 = s2;
Here p1 and p2 (==s2) will be different, because the S2 instance in C has an address offset.