FAQ 8.16 Is array-of Derived a kind-of array-of Base ?

FAQ 8.16 Is array-of Derived a kind-of array-of Base?

No! And the compiler usually doesn't detect this error.

This is another specific example of the general guideline presented earlier. For example, suppose class Base has some virtual functions:

 #include <iostream> using namespace std; class Base { public:   Base() throw();   virtual ~Base() throw();   virtual void f() throw(); }; Base::Base() { } Base::~Base() { } void Base::f() throw() { cout << "Base::f()\n" << flush; } 

Suppose class Derived has some data, such as integer i_:

 class Derived : public Base { public:   Derived() throw();   virtual void f() throw(); protected:   int i_; }; Derived::Derived() throw() : Base() , i_(42) { } void Derived::f() throw() { cout << "Derived::f()\n" << flush; } 

Making a Base pointer refer to the first element in an array-of Derived objects is okay, provided users never perform pointer arithmetic (such as applying the subscript operator) using the Base pointer. Subscripting into the array using the Base pointer is wrong since it will use sizeof(Base) for the pointer arithmetic rather than sizeof(Derived). Thus, subscripting into the array using the Base pointer may not refer to any Derived object:

 void sample(Base* b) throw() {   cout << "b[0].f(): " << flush;   b[0].f();   cout << "b[1].f(): " << flush;   b[1].f();                                          <-- 1 } int main() {   Derived d[10];   sample(d); } 

(1) Bang!

To understand what happened in function sample(), imagine a typical 32-bit computer that implements virtual functions in the usual way: a single virtual pointer in the object. In this case sizeof(Base) might be 4 (that is, one machine word for the virtual pointer), and sizeof(Derived) might be 8 (the Derived class objects have whatever size was in the Base plus the data from Derived). But since the compiler only knows that b points to Base in function sample(), it will use sizeof(Base) when computing subscripts. So b[1] will be 4 bytes after the beginning of the array, which is somewhere in the middle of object d[0]!

Regardless of the specifics of the machine used, it is very unlikely that b[1] will refer to the same address as d[1] since sizeof(Derived) is different than sizeof(Base). So the best possible outcome would be an immediate system crash (which is extremely likely; try it!).

This underscores the advantage of using an array-like class instead of using a C++ array. The compiler would have detected the error in the preceding problem if a vector<Derived> had been used rather than a Derived[] (vector<T> is the standard array-like template; see FAQ 28.13). For example, attempting to pass a vector<Derived> to sample(vector<Base>& a) would have caused a compile-time error message; see FAQ 8.17. (Remember: don't use pointer casts to "cover up" error messages. When you get an error message, fix the underlying problem rather than simply trying to get the compiler to stop generating error messages).



C++ FAQs
C Programming FAQs: Frequently Asked Questions
ISBN: 0201845199
EAN: 2147483647
Year: 2005
Pages: 566
Authors: Steve Summit

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net