This is the only Adapter code that I found in C++, and other codes are often not complete, showing just the adapter part, so i also find it hard to write my own code.
Well, it is working fine...
[...] i'm still trying to fully understand this [...]
So I assume it would help to explain the example in detail...
Problem for need of such adapter classes is typically that you have some legacy code you want to integrate or use into your own API - but you cannot or do not want to modify that legacy coce. A variation of the scenario is using two different and incompatible API together.
The idea now is providing an adapter/wrapper class that "transforms" an object of one API into an object of the other API (let's stay with the legacy scenario, then transforming a legacy API object into your own API object).
If you now use composition or private inheritance (composition is preferrable, see the links in the comments of sithereal's answer) is not really the point here. Important is that your adapter/wrapper class incorporates the legacy object in some way that is suitable so that it gets access to whatever it needs from.
The basic idea is that the adapter will kind of emulate being the base class using the functionality the legacy class provides.
Back to the example:
class Rectangle;
The abstract base class. It defines the interface any Rectangle class shall provide (in this case: the draw
function, which is pure virtual, i. e. has no implementation). Your own class(es) – lets call it OrdinaryRectangle
(no better idea - invent something up yourself...) – will simply inherit from the Rectangle base class and implement the draw function as needed.
Following this example, you will define the same way yyour own interface and provide an implementation for - or you have already. Possibly, you have the finished implementation of your own class, but you might yet have to extract the public interface into a new base class. OK, drifting away...
class LegacyRectangle;
The class coming from the other/legacy API. You might get instances of from your legacy API and feed them back into later. Converting these instances into your own API and back (e. g. by providing appropriate constructors in Rectangle and cast operators) – the alternative – might be too expensive for any reason (runtime overhead, coding effort, ...). So you wrap another class around, pretending to be an instance of your own rectangle implementation, but using the legacy rectangle internally.
class RectangleAdapter : public Rectangle, private LegacyRectangle
OK, example used private inheritance, so I'll follow, in spite of all the discussion around in the other answer...
Inheriting publicly from Rectangle (as does (must!) OrdinaryRectangle, too) is necessary to be able to handle RectanlgeAdapter just as if it was an OrdinaryRectangle (technically incorrect: better: as both inherit from Rectangle, both can be treated as a such - no matter which instance you actually have - in most situations, you won't even know!).
Inheriting privately from LegacyRectangle (or preferrably having an internal member of) provides you the internal instance of your legacy API object.
Constructor; nice, I'll ommit that one to explain... But: you might want to add copy and move constructors for your LegacyRectangle (a little bit dangerous wording, normally, these terms are applied for copying/moving instances of your own class - but you'll see) - this is expecially (only?) interesting if LegacyRectangle provides such constructors itself (in the classic meaning, though):
RectangleAdapter(LegacyRectangle const& lr) : LegacyRectangle(lr) { }
RectangleAdapter(LegacyRectangle&& lr) : LegacyRectangle(std::move(lr)) { }
(Above is incomplete, but should suffice to illustrate!)
virtual void draw()
{
cout << "RectangleAdapter: draw." << endl;
oldDraw();
}
Here we are at the core - we implement the interface of our own API by use of the legacy API. In the example, this is totally simple - we just use the oldDraw() function. In reality, this can achieve arbitrary complexity. Just to get a little more of it into: Imagine there was no oldDraw
, but instead drawBorder
and fillInterior
functions. You'd then have to use these inside your own draw
function.
This is the part where it can get really difficult. If you have problems there, you need to need to get more concrete, we then need to know the exact szenario(s) and detailed questions to be able to help you... Have a look at how to ask a good question and how to create a mcve before...