Derived class issues with arrays and casting in C++

I’m working my way through C++ FAQs book by Cline and Lomow, and it’s excellent. There’s lots of issues going on with inheritance, arrays and casting that could be a real pain to deal with towards the end of system development, but that you can nip in the bud and make life easier for yourself. For example, just knowing that an array of objects of a Derived class is NOT a kind-of array of objects of the Base class can prevent you a lot of headaches…

// Book: C++ FAQs by Cline & Lomow
// FAQ 136 & 137 - Is array-of Derived a kind-of array-of Base?
// Answer: NO!
 
#include <iostream>
using namespace std;
 
class Base
{
	protected:
		int i;
 
	public:
		Base() : i(42*42)      { }
		virtual ~Base()        { }
		virtual void service() { cout << "Base::service() called.\n" << flush; }
};
 
class Derived : public Base
{
	protected:
		// Add some extra things so that an object of type Derived is a different
		// size to an object of type Base
		int j;
		float k;
		unsigned long l;
 
	public:
		Derived() : Base(), j(42*42*42) { }
		virtual void service()          { cout << "Derived::service() called.\n" << flush; }
};
 
// Userland function
void useSubscript(Base *b)
{
	cout << "b[0].service(): " << flush; b[0].service();
	cout << "b[1].service(): " << flush; b[1].service(); // BOOM! Segfault!
 
	// This fails because the size of Base and the size of Derived are different:
	// "The fundamental problem is that a pointer to the first of an array-of-things
	// has exactly the same type as a pointer to a single thing. This was inherited
	// from C."
	//
	// In essence, as we're passing in Base pointers, in this case Base moves from
	// element to element in 16 byte intervals, but we actually provided an array
	// of Derived objects, which have a size of 32 bytes each, so b[1] starts
	// at b[0]+16, which is really only half-way through our first Derived element d[0]!
	//
	// The way to do this properly is to use a templatised container class instead.
	// If you tried to pass Array<Derived> as Array<Base> this would be caught at compile time.
}
 
int main()
{
    Derived d[10];
 
    cout << "Base has a size of   : " << sizeof(Base)    << " bytes." << endl;         // 16 bytes
    cout << "Derived has a size of: " << sizeof(Derived) << " bytes." << endl << endl; // 32 bytes
 
    useSubscript(d);
 
    return 0;
}

Good to know – now I just have to keep it in mind when I’m coding!