For example, if I have so many class that have same prefix in same platform:
in android:
Printer *p=new AndroidPrinter();
Writer *w=new AndroidWriter();
Connector *c=new AndroidConnector();
in iOS:
Printer *p=new IOSPrinter();
Writer *w=new IOSWriter();
Connector *c=new IOSConnector();
is it possible to define a part of class name like that:
#define PREFIX Android
int main(){
Printer *p=new PREFIXPrinter();
Writer *w=new PREFIXWriter();
Connector *c=new PREFIXConnector();
return 0;
}
instead of:
#define PLATFORM 0
#if PLATFORM==0
#define PRINTER AndroidPrinter
#else
#define PRINTER IOSPrinter
#endif
#if PLATFORM==0
#define WRITER AndroidWriter
#else
#define WRITER IOSWriter
#endif
#if PLATFORM==0
#define CONNECTOR AndroidConnector
#else
#define CONNECTOR IOSConnector
#endif
int main(){
Printer *p=new PRINTER();
Writer *w=new WRITER();
Connector *c=new CONNECTOR();
return 0;
}
You can use it inside a function, but it is not scoped to the function. So, in your example, the second definitions of a macro will be a redefinition and generate an error. You need to use #undef to clear them first.
A macro is a piece of code in a program that is replaced by the value of the macro. Macro is defined by #define directive. Whenever a macro name is encountered by the compiler, it replaces the name with the definition of the macro.
The double-number-sign or token-pasting operator (##), which is sometimes called the merging or combining operator, is used in both object-like and function-like macros. It permits separate tokens to be joined into a single token, and therefore, can't be the first or last token in the macro definition.
(C++11) The predefined identifier __func__ is implicitly defined as a string that contains the unqualified and unadorned name of the enclosing function. __func__ is mandated by the C++ standard and is not a Microsoft extension.
You could use a static factory pattern with some template specialization for this. You don't really need a fully-fledged abstract factory, because you won't be switching platform halfway through execution. This way, you can work out which factory implementation to use at compile-time with no overhead (assuming that your factory methods are inlined and just forward to operator new
).
Define a couple of dummy structs to act as platform identifiers:
struct Android{};
struct IOS{};
Write some factory implementations based on those dummy structs:
template <typename T>
struct ConcreteComponentFactory;
template <>
struct ConcreteComponentFactory<Android>
{
static Printer *CreatePrinter()
{ return new AndroidPrinter(); }
static Writer *CreateWriter()
{ return new AndroidWriter(); }
static Connector *CreateConnector()
{ return new AndroidConnector(); }
};
template <>
struct ConcreteComponentFactory<IOS>
{
static Printer *CreatePrinter()
{ return new IOSPrinter(); }
static Writer *CreateWriter()
{ return new IOSWriter(); }
static Connector *CreateConnector()
{ return new IOSConnector(); }
};
Work out what platform to use based on some macro:
#define PLATFORM 0
#if PLATFORM==0
using Platform = Android;
#else
using Platform = IOS;
#endif
Then typedef the instance for the platform you are working on:
using ComponentFactory = ConcreteComponentFactory<Platform>;
Now we can create instances of our objects and forget about what platform we are on:
Writer *a = ComponentFactory::CreateWriter();
If we need to know what platform we are on at some point, we can just refer to the Platform
typedef.
This approach is pretty flexible and far more type-safe than the macro-based version you have.
Demo
You can not have exactly the syntax you want. However, you can do some more preprocessor magic to have it working:
#define CONCAT_HELPER(a,b) a ## b
#define CONCAT(a,b) CONCAT_HELPER(a,b)
#define x ABC
#define MAKENAME(y) CONCAT(x,y)
int MAKENAME(def); // this defines ABCdef variable
int main() {
ABCdef = 0;
return 0;
}
However, it would be a better way to use another approach, such as namespace suggested in the comments, or even better an abstract factory, something like this:
class Factory {
public:
virtual Printer* getPrinter() = 0;
virtual Writer* getWriter() = 0;
};
class AndroidFactory: public Factory {
public:
virtual Printer* getPrinter() { return new AndroidPrinter(); }
virtual Writer* getWriter() { return new AndroidWriter(); }
};
// the same for IOS, or,
// if you really have such a similar code here,
// you can make a macros to define a factory
...
int main() {
#ifdef ANDROID
Factory* factory = new AndroidFactory();
#else
Factory* factory = new IOSFactory();
#endif
// now just pass factory pointer everywhere
doSomething(old, parameters, factory);
}
(Even better will be to use auto_ptr
s or even unique_ptr
s.)
(You can also make your factory a singleton if you want.)
UPDATE:
Another approach is to have two independent factory classes and just typedef
to use one of them:
class AndroidFactory { // no inheritance here
public:
Printer* getPrinter() {...} // no virtual here!
...
};
class IOSFactory {
...
};
#ifdef ANDROID
typedef AndroidFactory Factory;
#else
typedef IOSFactory Factory;
#endif
// note that we pass Factory* here
// so it will compile and work on both Android and IOS
void doSomething(int param, Factory* factory);
int main() {
Factory* factory = new Factory();
// and pass factory pointer around
doSomething(param, factory);
}
See also TartanLlama's answer for an more advanced version of this approach, including static functions to avoid passing a pointer around.
This approach has an advantage that everything is resolved at compile time and no virtual calls are made.
However, I do not think that virtual functions will be a real bottleneck, because being a factory it will not be called many times. I think your usage pattern will be something on the lines of
Foo* foo = factory.getFoo();
foo->doSomething();
and most of the time will be spend in the doSomething()
call, so getFoo()
virtual call overhead will not be a bottleneck.
At the same time, this approach has a disadvantage that it lacks proper inheritance structure and thus makes extension more difficult (and static functions would make extension even more difficult).
Imagine you will want to have a bit different factories for Android phones and Android tablets. With inheritance, you will simply have a basic AndroidBaseFactory
class that has common logic and two subclasses for phones and tablets replacing only what you need. Without inheritance you will have to copy all common functionality (even if it is just a return new AndroidFoo();
call) in both factory classes.
Also, unit testing and mocking is simpler with inheritance and pointers being passes around.
In fact, many of arguments of "singleton vs a bunch of static functions" apply here too.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With