【问题标题】:Changing type of variable using prepocessor's #ifdef使用前处理器的 #ifdef 更改变量类型
【发布时间】:2016-07-03 21:50:50
【问题描述】:

我有两个应用程序“服务器”和“客户端”,它们依赖于许多相同的代码。 他们需要以不同的方式与控制台交互。我不想编写一个处理这两种情况的类,而是想在两种不同的情况下包含两个不同的类。现在,在 Globals.h 和 Globals.cpp 我这样做:

Globals.h:

#ifdef SERVER
extern ConsoleUI ui;
#else
extern Logger ui;
#endif

Globals.cpp:

#include "Globals.h"
#ifdef SERVER
ConsoleUI ui;
#else
Logger ui;
#endif

(我在标题中也包含了守卫,但将它们留在这里)。

在服务器的主文件中,我定义:

#define SERVER

在客户端的主文件中,我使用:

#define CLIENT

但是,它们最终都创建了 Logger ui 而不是 ConsoleUI ui。 我知道这一点是因为服务器尝试调用存在于 ConsoleUI 和段错误中的函数,因为出于某种原因,他的“ui”属于“Logger”类型。

我确实意识到一种更简洁的方法可能是将 Globals 分成 GlobalsClient.h/.cpp 和 GlobalsServer.h/.cpp,但我想了解为什么上面的代码不起作用。

希望以前没有人问过这个问题,我搜索的所有内容都没有给我任何有用的点击。

【问题讨论】:

  • 一般来说,在 C++ 中实现你想要的东西有更好的方法。如果有很多通用代码,如何创建一个包含该代码的基类并拥有 2 个实现非通用代码的派生类?
  • 听起来是个坏主意!不过,您必须使用-DSERVER-DCLIENT 编译所有项目源,恐怕仅在main.cpp 中设置定义是不够的。

标签: c++ c-preprocessor


【解决方案1】:

您的代码可能失败的原因是,如果您执行#define SERVER 之类的操作,则会创建SERVER 符号。如果您在其他地方也有#define CLIENT,那么以下内容:

#include "Globals.h"
#ifdef SERVER
ConsoleUI ui;
#else
Logger ui;
#endif

实际上会沿着 ifdef SERVER 分支,这可能不是您想要的。

为了以您希望的方式进行条件编译,您需要使用来自命令行的#define 为服务器编译一次,为客户端编译一次。执行此操作的标志通常是-D

所以使用#ifdef 方法为服务器编译你会做类似的事情

g++ -DSERVER -o server_output_name

对于客户:

g++ -DCLIENT -o client_output_name

但是重要的是要认识到,一般来说,在 C++ 中实现您想要的东西有更好的方法。具体来说,您希望让语言为您进行类型检查,而不是依赖相对而言“不安全”的预处理器。如果有很多通用代码,如何创建一个包含该代码的基类并拥有 2 个实现非通用代码的派生类?

类似:

class UIBase{

protected:
 //all the common code
};


class UIServer : public UIBase{
//server specific code and implementation
};

class UIClient : public UIBase{
//client specific code and implementation
};

通过这种方式,您可以根据对象的类型创建对象,并让 c++ 语言确保根据上下文调用正确的代码。您可以通过这种方式获得一些类型安全性,这是 #define 方法所没有的。

【讨论】:

  • 这就是问题所在。谢谢!
  • 多个文件包含Globals.h(因为他们需要ui对象),但只有在主文件中我#define SERVER#define CLIENT,所以当其他文件包含Globals.h他们总是会沿着#else 路径并定义一个“Logger”而不是“ConsoleUI”。是的,我很可能最终会使用继承方法,但想了解为什么我的第一种方法不起作用。
【解决方案2】:

问题可能是您没有始终如一地定义SERVERCLIENT 每个人。将 Globals.h 更改为:

#ifdef SERVER
#ifdef CLIENT
#error "Both CLIENT and SERVER defined!"
#endif
#define ui ServerUI
extern ConsoleUI ui;
#elif defined(CLIENT)
#define ui ClientUI
extern Logger ui;
#else
#error "Neither CLIENT nor SERVER defined!"
#endif

现在,如果您的 SERVER 和/或 CLIENT 设置丢失或其他损坏,您将收到编译器或链接器错误,而不是运行时崩溃。

【讨论】:

  • 这是个好主意,谢谢!我将 shuttl87 的答案标记为使用 -D 标志进行快速修复的正确答案。但如果我以后需要这个,我会尝试使用这样的结构。
【解决方案3】:

确保在主 cpp 中包含“Globals.h”之前放置“#define SERVER”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-01
    • 1970-01-01
    • 2013-01-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多