我正在编写一个类(在头文件myClass.h
和实现文件myClass.cpp
中分隔),我希望将它与标准C ++和Qt框架一起使用。由于代码中的差异非常小(我想尝试一次),我决定#define USINGQT 1
以便通过
#if USINGQT==1
//Qt code
#else
//standard code
#endif
现在我得出的结论是,在整个班级中使用QString
而不是std::string
时,如果"激活" USINGQT
开关。但是,上面的方法会使代码非常混乱。我的解决方案(在头文件中):
#if USINGQT==1
#include <QString>
#define string QString
#else
#include <string>
#define string std::string
#endif
现在回答问题:
将文件视为
---myclass.h-------------------------
#ifndef MYCLASS_H
#define MYCLASS_H
#define USINGQT 1 //1=on, else off
#if USINGQT==1
#include <QString>
#define string QString
#else
#include <string>
#define string std::string
#endif
namespace mySpace {
class MyClass {
string qtOrStd;
string foo();
//etc...
};
} //namespace
#endif //MYCLASS_H
-------------------------------------
---myclass.cpp-----------------------
#include "myclass.h"
using namespace mySpace;
//implementations
string MyClass::foo() //string symbol occurs, as does the USINGQT
-------------------------------------
#undef
和string
符号USINGQT
的正确位置在哪里?在头文件的末尾(这将需要重新定义和#34;未定义&#34;在实现文件中)或仅在实现文件的末尾?
我也应该将string
宏大写,不应该......? &GT;&GT;
如果我将宏定义放在命名空间中,我会收到大约。 800个错误消息,条目如&#34;没有mySpace成员:: std&#34;等等。如果没有进一步的信息,你能说些什么吗?否则它编译得很好。
typedef
s - 在宏观情况下,我猜,我应该将#undef
放在实现文件的末尾。因为包含警卫而不会重新定义宏。
答案 0 :(得分:4)
USINGQT
切换为等于1,您只需#define USINGQT
,然后使用#ifdef USINGQT
作为if语句。// --------------一些配置文件------------- =
#define USINGQT
// -------------- MyClass.h --------------------=
// Header guard
#ifndef MyClass
#define MyClass
// Conditional Header types
#ifdef USINGQT
// QT OPTION
typedef QString my_string;
#else
// Not QT
typedef std::string my_string;
#endif
class MyClass {
public:
my_string some_string;
MyClass()
{
my_string = "hello world";
}
};
#endif
答案 1 :(得分:1)
除非另一个文件试图重新定义它,否则 到#undef
个宏。在使用它之前,你不能#undef
一个宏,因此,如果你在标题中#define
一个宏并希望在包含它的文件中使用它标题,然后你不能在该标题中#undef
。
1)#undef字符串和USINGQT符号的正确位置在哪里?在头文件的末尾...
仅如果您在该标题中使用它...但您显然确实使用了包含标题的文件,因此否。
或仅在实施文件的末尾?
在实现文件末尾取消定义宏是没有意义的,因为在宏应用的文件结尾之后将不再有代码。让它保持定义。
2)我也应该把字符串宏大写,我不应该......? &GT;&GT;
您不必将宏大写,但它是一种惯例。也就是说,定义一个与标准类同名的宏只是在寻找麻烦。您应该在此处使用typedef
而不是宏,以便在名称冲突时获取有意义的错误消息。并使用其他名称string_t
或在命名空间中定义typedef
。
3)如果我将宏定义放在命名空间内,我会收到大约。 800错误消息
错误不是来自定义命名空间内的宏。错误来自使用宏 - 如果它们是命名空间的一部分。例如,如果你说:
namespace mySpace {
#define string std::string
}
mySpace::string s;
然后string
将替换为std::string
,类型名称将变为mySpace::std::string
。由于您尚未在std
中定义mySpace
命名空间,因此这是错误的。您需要了解的是命名空间对预处理器宏没有任何影响。这使得更难避免名称冲突,这是您通常想要避免使用预处理器宏的一个原因。
如果USINGQT
宏适用于代码的所有,使得所有文件必须相同,您可能根本不想在标题中定义它,而是通过它作为编译器的参数。这样,您可以轻松地使用不同的值进行编译而无需更改文件。
关于您的修改:
即使您希望在另一个文件中以不同方式定义宏,然后在实现结束时取消定义它也没有效果,因为包含标头的文件不会包含实现文件。您应该避免需要多个不同定义(或缺少定义)宏的情况,但是如果您处于这种情况,那么是的,您唯一的解决方案是单独定义它每个需要它的文件然后在任何需要它的头的末尾取消定义。但是你不是在这种情况下,因为你可以使用类型别名。
答案 2 :(得分:1)
我认为#undef
宏没有任何理由。当然,您希望所有您的代码使用该宏的一个状态进行编译?那么你就不需要#undef
了。
但是,我强烈建议您使用typedef
作为string
定义。无论如何,这将更清楚,你不会考虑大写它,你甚至可以把它放入你的命名空间。如果需要访问全局命名空间,请使用::
:
#define USINGQT
#ifdef USINGQT
#include <QString>
#else
#include <string>
#endif
namespace mySpace {
#ifdef USINGQT
typedef ::QString string;
#else
typedef ::std::string string;
#endif
}
另请注意(如上所示)如果您只需要宏的布尔值,则不需要将其设为1
或0
,只需使用#ifdef
/ #ifndef
。
在此之后,在.cpp
中,只需使用mySpace::string
,就不用担心宏。