C++ 如何将类名的一部分定义为宏?

C++ 如何将类名的一部分定义为宏?,c++,C++,例如,如果在同一平台中有这么多具有相同前缀的类: 在android中: Printer *p=new AndroidPrinter(); Writer *w=new AndroidWriter(); Connector *c=new AndroidConnector(); 在iOS中: Printer *p=new IOSPrinter(); Writer *w=new IOSWriter(); Connector *c=new IOSConnector(); 可以这样定义类名的一部分吗:

例如,如果在同一平台中有这么多具有相同前缀的类:

在android中:

Printer *p=new AndroidPrinter();
Writer *w=new AndroidWriter();
Connector *c=new AndroidConnector();
在iOS中:

Printer *p=new IOSPrinter();
Writer *w=new IOSWriter();
Connector *c=new IOSConnector();
可以这样定义类名的一部分吗:

#define PREFIX Android

int main(){
    Printer *p=new PREFIXPrinter();
    Writer *w=new PREFIXWriter();
    Connector *c=new PREFIXConnector();
    return 0;
}
而不是:

#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;
}

你不能<代码>PREFIXPrinter()将是一个名为
PREFIXPrinter()的函数
AndroidPrinter()

您可以这样做:

#define PREFIX(a) Android##a
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);
}
用法:

PREFIX(Printer)();

它将调用
AndroidPrinter()

您无法获得所需的语法。但是,您可以使用更多的预处理器魔法使其正常工作:

#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;
}
但是,使用另一种方法会更好,例如注释中建议的名称空间,或者更好的是使用抽象工厂,例如:

#define PREFIX(a) Android##a
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);
}
(更好的方法是使用
auto_ptr
s甚至
unique_ptr
s。)

(如果您愿意,也可以将工厂设置为单件。)

更新:

另一种方法是有两个独立的工厂类,只需
typedef
使用其中一个:

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);
}
另请参见TartanLlama的答案,了解此方法的更高级版本,包括避免传递指针的静态函数

这种方法的优点是在编译时解决所有问题,并且不进行虚拟调用

然而,我不认为虚拟函数会成为真正的瓶颈,因为作为一个工厂,它不会被多次调用。我认为您的使用模式将与

Foo* foo = factory.getFoo();
foo->doSomething();
而且大部分时间都花在
doSomething()
调用上,因此
getFoo()
虚拟调用开销不会成为瓶颈

同时,这种方法的缺点是缺乏适当的继承结构,从而使扩展更加困难(而静态函数会使扩展更加困难)

想象一下,你想为安卓手机和安卓平板电脑建立一些不同的工厂。通过继承,您只需拥有一个基本的
AndroidBaseFactory
类,该类具有通用逻辑和两个用于手机和平板电脑的子类,只需替换您需要的内容即可。如果没有继承,您将不得不复制两个工厂类中的所有公共功能(即使它只是一个
returnnewandroidfoo();
调用)

此外,通过传递继承和指针,单元测试和模拟更简单


事实上,“单例vs一堆静态函数”的许多参数在这里也适用。

您可以使用带有一些模板专门化的静态工厂模式。您并不真正需要一个成熟的抽象工厂,因为您不会在执行的中途切换平台。这样,您就可以在编译时计算出要使用哪个工厂实现,而无需任何开销(假设您的工厂方法是内联的,只需转发到
操作符new

定义两个虚拟结构作为平台标识符:

struct Android{};
struct IOS{};
基于这些虚拟结构编写一些工厂实现:

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(); }
};
然后键入您正在使用的平台的实例:

using ComponentFactory = ConcreteComponentFactory<Platform>;
如果我们需要知道我们在什么平台上,我们可以参考
platform
typedef

这种方法非常灵活,并且比基于宏的版本更安全


这是不可能的,但您可以用类似的推广效果做其他事情

  • 正如@Biffen指出的,您可以使用

  • 正如@Petr所指出的,您可以使用

  • 正如@Petr在他的回答中指出的,您可以使用一些预处理器魔法

  • 你可以用


  • 你不能改用名称空间吗?例如,
    Android::Printer
    Android::Writer
    ,等等。名称空间似乎是最好的解决方案(比预处理器black magick好得多)。它只是更易于维护/阅读。你不应该使用工厂。您在运行时会遇到很多虚拟调用,这些调用本可以在编译时解决,并消除了一些内联的可能性。@kirbyfan64sos,我已经更新了答案,特别是讨论了为什么我认为real factory的优势大于劣势。我喜欢这样,因为一切都是在编译时进行的。