views:

383

answers:

5

To follow from my previous question about virtual and multiple inheritance (in a cross platform scenario) - after reading some answers, it has occurred to me that I could simplify my model by keeping the server and client classes, and replacing the platform specific classes with #ifdefs (which is what I was going to do originally).

Will using this code be simpler? It'd mean there'd be less files at least! The downside is that it creates a somewhat "ugly" and slightly harder to read Foobar class since there's #ifdefs all over the place. Note that our Unix Foobar source code will never be passed to the compiler, so this has the same effect as #ifdef (since we'd also use #ifdef to decide what platform specific class to call).

class Foobar {
public:
  int someData;

#if WINDOWS
  void someWinFunc1();
  void someWinFunc2();
#elif UNIX
  void someUnixFunc1();
  void someUnixFunc2();
#endif

  void crossPlatformFunc();
};

class FoobarClient : public Foobar;
class FoobarServer : public Foobar;

Note: Some stuff (ctor, etc) left out for a simpler example.

Update:

For those who want to read more into the background of this issue, I really suggest skimming over the appropriate mailing list thread. Thing start to get interesting around the 3rd post. Also there is a related code commit with which you can see the real life code in question here.

A: 

Having #ifdefs for platform specific code is idiomatic; especially since code for one platform won't even compile if it's enabled on another. Sounds like a good approach to me.

Terry Mahaffey
+2  A: 

If you're fully sure that you won't use functions from the other OS on the one compiled, then using ifdef's has a lot of advantages:

  1. Code and variables non used won't be compiled into the executable (however smart-linking helps here a bit)
  2. It will be ease to see what code is live
  3. You will be able to easily include platform dependent files.

However, classing based on OS can still have it's benefits:

  1. You'll be able to be sure that the code compiles on all platforms when doing changes for one
  2. The code and design will be cleaner

The latter is achieved by ifdefing platform-specific code in the class bodies themselves, or just ifdefing out the non-supported OS instances in compilation.

Kornel Kisielewicz
+9  A: 

Preferably, contain the platform dependant nature of the operations within the methods so the class declaration remains the same across platforms. (ie, use #ifdefs in the implementations)

If you can't do this, then your class ought to be two completely separate classes, one for each platform.

Autopulated
This is definitely the way to go, if possible. Provided the calling code doesn't care about the platform, though, it's all (mostly) good.
brone
In our case the old code (which we're refactoring) is tightly coupled to each platform, so unfortunately I'm not sure this is an option for us.
nbolton
+4  A: 

My personal preference is to push ifdef magic into the make files, so the source code stays as clean as possible. Then have an implementation file per platform. This of course implies you can come up with an interface common for all your supported systems.

Edit:

One common way of getting around such a lower denominator design for cross-platform development is an opaque handle idiom. Same idea as ioctl(2) escape route - have a method returning opaque forward-declared structure defined differently for each platform (preferably in the implementation file) and only use it when common abstraction doesn't hold.

Nikolai N Fetissov
+2  A: 

My preference is to push platform specific issues to the leaf-most modules and try to wrap them into a common interface. Put the specific methods, classes and functions into separate translation units. Let the linker and build process determine which specific translation units to combine. This makes for much cleaner code and easier debugging times.

From experience, I had a project that used #ifdef VERSION2. I spent a week in debugging because one module used #ifdef VERSION_2. A subtlety that would be easier to catch if all the version 2 specific code was in version 2 modules.

Thomas Matthews