Reputation: 3065
Consider following code:
#include <iostream>
using namespace std;
class Base
{
public:
int foo;
};
class Derived : public Base
{
public:
float bar;
};
int main()
{
Base** baseArr = new Base*[30];
for (int i=0; i<30; i++)
{
Derived* derived = new Derived();
derived->foo = i;
derived->bar = i * 2.5;
baseArr[i] = derived;
}
//Notice this!
Derived** derivedArr = (Derived**)(baseArr);
for (int i=0; i<30; i++)
cout << "My Base " << i << ": " << derivedArr[i]->foo << ", " << derivedArr[i]->bar << endl;
return 0;
}
Is it safe to do this array to array cast? The pointer size is same across the program, so it sounds like I won't get any padding errors. However, I know that the correct way to do this is to iterate through each element and cast it individually.
However, Im trying to utilize this kind of cast to move my template public functions implementations to .cpp file by using non-generic private function returning array, so I can be sure that my Base
array will contain only specific Derived
pointers.
private:
Base** Find(function<bool(Base*)> Predicate, int& N); //Implemented in .CPP
public:
template <class T> T** FindByType(int &N) //T is derived from Base
{
//Safe?
return (T**)(Find(
[](Base* b)->bool { return typeid(T) == typeid(b); },
N));
};
This is just a simplified example, of course. I've got number of reasons to use RTTI in this case. N is used to controll array size.
I am wondering if this unsafe cast will fail with multi-inheritance, like for example Derived
class would also inherit OtherBase
and I'd like to cast to OtherBase**
, I'd also like to know if by any chance I reach undefined behaviour with this cast, or any potential problems I may encounter if I decide to use this construct.
Upvotes: 0
Views: 132
Reputation: 36483
No, this is unsafe.
If a program attempts to access the stored value of an object through a glvalue of other than one of the following types the behavior is undefined:
- the dynamic type of the object,
- a cv-qualified version of the dynamic type of the object,
- a type similar (as defined in 4.4) to the dynamic type of the object,
- a type that is the signed or unsigned type corresponding to the dynamic type of the object,
- a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic type of the object,
- an aggregate or union type that includes one of the aforementioned types among its elements or non-static data members (including, recursively, an element or non-static data member of a subaggregate or contained union),
- a type that is a (possibly cv-qualified) base class type of the dynamic type of the object,
- a
char
orunsigned char
type.
Shamelessly stolen from Ben
None of those cases is true in the case of casting Base**
to Derived**
.
Upvotes: 1
Reputation: 118350
No it is not safe.
A pointer to Derived
is not the same thing as a pointer to Base
. A pointer to Derived
can be converted to a pointer to Base
, but the end result is a different pointer.
And because a pointer to Derived
is not the same thing as a pointer to Base
, a pointer to a pointer to Derived
is also not the same thing as a pointer to a pointer to Base
.
Upvotes: 2