Partial class definition on C++?

or you could try PIMPL

common header file:

class Test
{
public:
    ...
    void common();
    ...
private:
    class TestImpl;
    TestImpl* m_customImpl;
};

Then create the cpp files doing the custom implementations that are platform specific.


You can't partially define classes in C++.

Here's a way to get the "polymorphism, where there's only one subclass" effect you're after without overhead and with a bare minimum of #define or code duplication. It's called simulated dynamic binding:

template <typename T>
class genericTest {
public:
    void genericMethod() {
        // do some generic things
        std::cout << "Could be any platform, I don't know" << std::endl;
        // base class can call a method in the child with static_cast
        (static_cast<T*>(this))->doClassDependentThing();
    }
};

#ifdef _WIN32
    typedef Win32Test Test;
#elif MAC
    typedef MacTest Test;
#endif

Then off in some other headers you'll have:

class Win32Test : public genericTest<Win32Test> {
public:
    void win32Method() {
        // windows-specific stuff:
        std::cout << "I'm in windows" << std::endl;
        // we can call a method in the base class
        genericMethod();
        // more windows-specific stuff...
    }
    void doClassDependentThing() {
        std::cout << "Yep, definitely in windows" << std::endl;
    }
};

and

class MacTest : public genericTest<MacTest> {
public:
    void macMethod() {
        // mac-specific stuff:
        std::cout << "I'm in MacOS" << std::endl;
        // we can call a method in the base class
        genericMethod();
        // more mac-specific stuff...
    }
    void doClassDependentThing() {
        std::cout << "Yep, definitely in MacOS" << std::endl;
    }
};

This gives you proper polymorphism at compile time. genericTest can non-virtually call doClassDependentThing in a way that gives it the platform version, (almost like a virtual method), and when win32Method calls genericMethod it of course gets the base class version.

This creates no overhead associated with virtual calls - you get the same performance as if you'd typed out two big classes with no shared code. It may create a non-virtual call overhead at con(de)struction, but if the con(de)structor for genericTest is inlined you should be fine, and that overhead is in any case no worse than having a genericInit method that's called by both platforms.

Client code just creates instances of Test, and can call methods on them which are either in genericTest or in the correct version for the platform. To help with type safety in code which doesn't care about the platform and doesn't want to accidentally make use of platform-specific calls, you could additionally do:

#ifdef _WIN32
    typedef genericTest<Win32Test> BaseTest;
#elif MAC
    typedef genericTest<MacTest> BaseTest;
#endif

You have to be a bit careful using BaseTest, but not much more so than is always the case with base classes in C++. For instance, don't slice it with an ill-judged pass-by-value. And don't instantiate it directly, because if you do and call a method that ends up attempting a "fake virtual" call, you're in trouble. The latter can be enforced by ensuring that all of genericTest's constructors are protected.


Try inheritance

Specifically

class AllPlatforms {
public:
    int common();
};

and then

class PlatformA : public AllPlatforms {
public:
    int specific();
};

This is not possible in C++, it will give you an error about redefining already-defined classes. If you'd like to share behavior, consider inheritance.

Tags:

C++