How to create an API for an existing codebase?
I'm trying to create a public C++ API for a private code base that is
also written in C++. My approach goes like this:
* Define a common base class for API objects. It holds a pointer to
the base class of the private library.
* Create a corresponding API class for each private class.
* Don't put any implementation details in the API class but simply
forward all method calls to the private classes.
This seemed like a reasonable approach. However, in reality it turns
out to be a very unpractical approach and requires an abnormal amount
of casting to make it work.
Here are some code snippets that illustrate the problem:
// Note: the complete code sample can also be found online here:
// http://stacked-crooked.googlecode.com/svn/trunk/PlayGroundCpp/WrapAPI/ProblematicVersion
//
// The existing private codebase (declarations only):
//
// Base class for all Core classes.
class CoreObject
{
public:
virtual ~CoreObject();
};
class Interface;
class Stream;
class Server : public CoreObject
{
public:
Interface * createInterface();
private:
std::vector<Interface*> mInterfaces;
};
class Interface : public CoreObject
{
public:
void addStream(Stream * stream);
const Stream * getStreamByIndex(std::size_t index) const;
std::size_t streamCount() const;
private:
std::vector<Stream*> mStreams;
};
//
// The API declarations (so far so good):
//
class APIObject
{
public:
APIObject(Core::CoreObject * inCoreObject);
virtual ~APIObject();
Core::CoreObject * getCoreObject();
const Core::CoreObject * getCoreObject() const;
void setCoreObject(Core::CoreObject * inCoreObject);
private:
Core::CoreObject * mCoreObject;
};
class APIServer : public APIObject
{
public:
APIServer();
APIInterface * createInterface();
};
class APIInterface : public APIObject
{
public:
APIInterface();
void addStream(APIStream * stream);
const APIStream * getStreamByIndex(std::size_t index) const;
APIStream * getStreamByIndex(std::size_t index);
std::size_t streamCount() const;
};
//
// The API implementation (here the problems become visible)
//
APIInterface * APIServer::createInterface()
{
Core::Server * coreServer =
static_cast<Core::Server*>(getCoreObject());
Core::Interface * coreInterface = coreServer->createInterface();
APIInterface * result(new API::APIInterface);
result->setCoreObject(coreInterface);
return result;
}
void APIInterface::addStream(APIStream * apiStream)
{
Core::Stream * coreStream = static_cast<Core::Stream *>(apiStream-
getCoreObject());
Core::Interface * coreInterface =
static_cast<Core::Interface*>(getCoreObject());
coreInterface->addStream(coreStream);
}
const APIStream * APIInterface::getStreamByIndex(std::size_t index)
const
{
const Core::Interface * coreInterface = static_cast<const
Core::Interface*>(getCoreObject());
const Core::Stream * coreStream = coreInterface-
getStreamByIndex(index);
// Now how I get the the APIStream object?
throw;
}
std::size_t APIInterface::streamCount() const
{
const Core::Interface * coreInterface = static_cast<const
Core::Interface*>(getCoreObject());
return coreInterface->streamCount();
}
As you can see it doesn't really work well.
Where did I go wrong with my design? How can it be improved?
Grts,
Francis
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]