The Fragile Base Class Problem


	
Resolution is the process of replacing names by relative 
addresses and offsets. Normally resolution occurs during 
compilation and linking, which occurs before loading and 
execution. 

This creates a special problem in C++ called the Fragile 
Base Class Problem (also known as the Fragile Super Class 
Problem and the Constant Recompilation Problem). For 
example, assume the following class is declared and compiled:

   class Employee {
      private:
         char *name;
         int ssn;
         double salary;
      public:
         // etc.
   }

Later a derived class is declared and compiled:

   class Secretary: public Employee {
      private:
         int wpm; // typing speed in words/minute
      public:
         void display() { cout << wpm; }
         // etc.
   }

According to the rules of object layout dictated by the C++ 
compiler, a Secretary object is an Employee object extended 
by an integer variable (i.e. wpm). Hence the occurence of 
wpm inside display() will be bound to the relative address:

   this + offset(wpm)

where

   offset(wpm) = sizeof(Employee) + a little bit

This binding will occur at link time if Employee and Secretary 
are contained in seperate files.

Now assume the Employee class is modified to contain an extra 
field:

   class Employee {
      private:
         char *name;
         int ssn;
         double salary;
         int tenure; // = # years on the job
      public:
         // etc.
   }
   
Since sizeof(Employee) has changed, the Secretary::display() 
method contains the wrong offset for wpm, hence must be 
recompiled.

Java avoids this problem by reversing the usual "link then load" 
order. This is possible because the byte code produced by a
Java compiler may contain unresolved names (i.e. symbolic 
references). 

The corresponding Java declarations are:

   class Employee {
      private String name;
      private int ssn;
      private double salary;
      // etc.
   }

and

   class Secretary extends Employee {
      private int wpm;
      public void display(System.out.println(wpm); }
      // etc.
   }

First the class Secretary is loaded into memory by a class
loader object. This causes the Employee class to be loaded.

Next the Secretary class is linked. This is a four step
process:

   1. verify opcodes, jump targets, type consistencies, etc.
   2. allocate memory for static variables
   3. resolve symbolic references (or put it off until later!)
   4. initialize static variables

Finally, main() is called.

Now suppose the Employee class is redefined:

   class Employee {
      private String name;
      private int ssn;
      private double salary;
      private int tenure; // new field
      // etc.
   }

Again the old Secretary class is loaded along with the new
Employee class. Following the load phase, the link phase
resolves all symbolic references. This includes replacing
the occrence of the name wpm inside display() with an offset
which (may) depend on sizeof(Employee), but since this
occurs AFTER the new Employee class has been loaded, the
correct offset is computed, hence there is no need to 
recompile the Secretary class!

Two final observations:

1. Resolution may be postponed until instance creation time,
   or even until execution time.

2. Unlike the C++ compiler, the Java compiler doesn't determine
   object layout. (This is determined by the loader.) Hence
   the offset of wpm does not necessarily depend on sizeof(Employee)
   in Java.

See 
http://java.sun.com/doc/language_environment for more info.


Last modified:
Current visitor:
You are the visitor
Return to Index