|
||||
|
Section 21:
|
[21.4] Is an array of Derived a kind-of array of Base?
Nope. This is a corollary of the previous FAQ. Unfortunately this one can get you into a lot of hot water. Consider this:
class Base {
public:
virtual void f(); // 1
};
class Derived : public Base {
public:
...
private:
int i_; // 2
};
void userCode(Base* arrayOfBase)
{
arrayOfBase[1].f(); // 3
}
int main()
{
Derived arrayOfDerived[10]; // 4
userCode(arrayOfDerived); // 5
...
}
The compiler thinks this is perfectly type-safe. Line 5 converts a Derived*
to a Base*. But in reality it is horrendously evil: since Derived is
larger than Base, the pointer arithmetic done on line 3 is incorrect: the
compiler uses sizeof(Base) when computing the address for
arrayOfBase[1], yet the array is an array of Derived, which means the
address computed on line 3 (and the subsequent invocation of member function
f()) isn't even at the beginning of any object! It's smack in the middle of
a Derived object. Assuming your compiler uses the usual approach to
virtual functions, this will reinterpret the
int i_ of the first Derived as if it pointed to a virtual table, it
will follow that "pointer" (which at this point means we're digging stuff out
of a random memory location), and grab one of the first few words of memory at
that location and interpret them as if they were the address of a C++ member
function, then load that (random memory location) into the instruction pointer
and begin grabbing machine instructions from that memory location. The chances
of this crashing are very high.
The root problem is that C++ can't distinguish between a pointer-to-a-thing and a pointer-to-an-array-of-things. Naturally C++ "inherited" this feature from C. NOTE: If we had used an array-like class (e.g., std::vector<Derived> from the standard library) instead of using a raw array, this problem would have been properly trapped as an error at compile time rather than a run-time disaster. (Note: this FAQ has to do with public inheritance; private and protected inheritance are different.) |
|||