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

ggr*_*grr 16 c++

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

在android中:

Printer *p=new AndroidPrinter();
Writer *w=new AndroidWriter();
Connector *c=new AndroidConnector();
Run Code Online (Sandbox Code Playgroud)

在iOS中:

Printer *p=new IOSPrinter();
Writer *w=new IOSWriter();
Connector *c=new IOSConnector();
Run Code Online (Sandbox Code Playgroud)

可以像这样定义类名的一部分:

#define PREFIX Android

int main(){
    Printer *p=new PREFIXPrinter();
    Writer *w=new PREFIXWriter();
    Connector *c=new PREFIXConnector();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

代替:

#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;
}
Run Code Online (Sandbox Code Playgroud)

Tar*_*ama 18

您可以使用静态工厂模式以及一些模板专门化.你真的不需要一个完全成熟的抽象工厂,因为你不会在执行过程中途切换平台.这样,您可以计算出在编译时使用哪个工厂实现而没有开销(假设您的工厂方法是内联的并且只是转发operator new).

定义一些虚拟结构以充当平台标识符:

struct Android{};
struct IOS{};
Run Code Online (Sandbox Code Playgroud)

根据这些伪结构编写一些工厂实现:

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(); }
};
Run Code Online (Sandbox Code Playgroud)

根据一些宏来确定要使用的平台:

#define PLATFORM 0
#if PLATFORM==0
using Platform = Android;
#else
using Platform = IOS;
#endif
Run Code Online (Sandbox Code Playgroud)

然后键入dede您正在处理的平台的实例:

using ComponentFactory = ConcreteComponentFactory<Platform>;
Run Code Online (Sandbox Code Playgroud)

现在我们可以创建对象的实例,忘记我们所处的平台:

Writer *a = ComponentFactory::CreateWriter();
Run Code Online (Sandbox Code Playgroud)

如果我们需要知道我们在某个时刻处于什么平台,我们可以参考Platformtypedef.

这种方法非常灵活,比基于宏的版本更加类型安全.

演示


Pet*_*etr 11

你不能拥有你想要的语法.但是,您可以执行更多预处理器魔术以使其正常工作:

#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;
}
Run Code Online (Sandbox Code Playgroud)

但是,这是使用其他方法的更好方法,例如评论中建议的命名空间,甚至更好的抽象工厂,如下所示:

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);
}
Run Code Online (Sandbox Code Playgroud)

(更好的是使用auto_ptrs甚至unique_ptrs.)

(如果需要,您也可以让您的工厂成为单身人士.)

更新:

另一种方法是拥有两个独立的工厂类,只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);
}
Run Code Online (Sandbox Code Playgroud)

另请参阅TartanLlama对此方法的更高级版本的回答,包括避免传递指针的静态函数.

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

但是,我认为虚拟功能不会成为真正的瓶颈,因为作为工厂它不会被多次调用.我认为你的使用模式会有所不同

Foo* foo = factory.getFoo();
foo->doSomething();
Run Code Online (Sandbox Code Playgroud)

并且大部分时间都会花在doSomething()通话上,因此getFoo()虚拟通话开销不会成为瓶颈.

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

想象一下,你会想要为Android手机和Android平板电脑设置一些不同的工厂.通过继承,您将拥有一个AndroidBaseFactory具有通用逻辑的基本类和两个用于手机和平板电脑的子类,只替换您需要的内容.如果没有继承,则必须return new AndroidFoo();在两个工厂类中复制所有常用功能(即使只是一个调用).

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

事实上,"单身与一系列静态函数"的许多论点也适用于此.


Jah*_*hid 8

你不能.PREFIXPrinter();将是一个名为PREFIXPrinter();not 的函数AndroidPrinter();

你可以这样做:

#define PREFIX(a) Android##a
Run Code Online (Sandbox Code Playgroud)

用法:

PREFIX(Printer)();
Run Code Online (Sandbox Code Playgroud)

它会打电话 AndroidPrinter()