Gotcha #33: Misunderstanding Pointer-to-Pointer-to-Base Conversion
We face a similar situation with pointers to pointers to derived classes:
D1 d1;
D1 *d1p = &d1; // OK
B **ppb1 = &d1p; // error, fortunately
D2 *d2p;
B **ppb2 = &d2p; // error, fortunately
*ppb2 = *ppb1; // now d2p points to a D1!
Look familiar? Just as the const-conversion property doesn't hold if one introduces another level of indirection, the same is the case with the is-a property. While a pointer to a derived class is-a pointer to a public base, a pointer to a pointer to a derived class is not a pointer to a pointer to a public base. As with the analogous const example, the situation that results in an error initially looks contrived. However, it's easy to construct a situation that produces an error as a cooperative effort between a bad interface design and an incorrect use of the interface:
void doBs( B *bs[], B *pb ) {
for( int i = 0; bs[i]; ++i )
if( somecondition( bs[i], pb ) )
bs[i] = pb; // oops!
}
// . . .
extern D1 *array[];
D2 *aD2 = getMeAD2();
doBs( (B **)array, aD2 ); // another casted death wish . . .
Once again, the developer assumes the compiler is in error and circumvents the type system with a cast. In this case, though, the designer of the function interface has a lot to answer for as well. A safer design would have employed a container that didn't permit spoofing by cast, as an array does.
|