Up to: Mika Raento's Symbian Programming pages

Symbian Programming - Splitting interface and implementation

Splitting the interface and implementation of a C++ class is a good idea for two reasons:

Stroustrup describes the basic method and rationale for the split. The idea is that you provide an abstract base class in your header file with only those methods defined you want to be public, a factory method, and only the headers included needed. Then in your cpp file you define an implementation class that inherits from the abstract one, create an object of this class in the factory method and include all the headers needed for the implementation. The ideas work really well for Symbian as well, with a couple of restrictions and notes.

See mms.h and mms.cpp for an example of a class that really benefits from this split. It has a lot of members, functions and includes that the implementation needs while the interface is really simple (note that it doesn't compile out-of-the box since it needs some additional headers from our project).

The symbian specific things to note are:

  1. This really only works for C classes. For an R class you might split the implementation into a helper class, use a forward declaration for that class in the header and get most of the benefits. The Open and Close should then create and destroy the helper object. (I don't actually know if this really works or is a good idea. You don't tend to write so many R classes in user-level code.)
  2. The abstract interface has to inherit from CBase or more specifically from the most derived C class the implementation needs (like CActive, CAknView) unless you are willing to give up the possibility of putting it on the CleanupStack.
  3. For the factory method provide the Symbian NewL, and add the interface class as a friend to the implementation class (or make the constructor and ConstructL of the implementation class public).
  4. (Remember to make the destructor virtual, otherwise you'll always leak memory. This isn't Symbian specific, but is too important to skip).

It's a really good idea to do this from the beginning and for all classes in a larger project. We didn't realize that and do suffer from overlong compile times as a result. I find it pretty weird that the Symbian headers are not structured this way, as it would both help compile times and serve as a good example for others.

Of course this doesnt' work when you are meant to derive from the class provided. So consider this to be Symbian-speak for Java's final.

By the way: I don't think that forward declarations a reasonable alternative. If you do the split as shown here, you only need to include headers in .h file for those classes that are used in your method parameters - which shouldn't be that many, and as the class which uses your header most probably has to include their real definitions the speedup isn't that great (the include-guard will keep the file from being processed and it's probably in the cache). And since all your other classes are split the same way, the header dependencies should be much more shallow, and the reading of a few system headers won't kill the single unit being compiled. You can use forward declarations in the cases where you need to squeeze out the last bit of overhead.

Mika Raento, mikie(at)iki.fi