C++ FAQ Celebrating Twenty-One Years of the C++ FAQ!!!
(Click here for a personal note from Marshall Cline.)
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.)