我想定义私有和受保护的公共。
1 2
| #define private public
#define protected public |
这在C ++中是安全的吗?
-
你为什么这么想?它可能不会改变程序的运行时行为,但它会禁用许多非常有用的编译器诊断。显示使您想要这样做的代码!
-
viva64.com/en/b/0146
-
但它很有趣。
-
您可能具有无法解析的符号,因为名称修改可以使用可见性。
-
它与#define TRUE FALSE一样不安全
-
它和#define while if一样疯狂
-
在生产代码中做一件疯狂的事情,但对测试可能有意义。我永远不会为新测试做这个,但是已经完成了将测试中的遗留代码包装起来。然而,这不是"解决方案",而是在重构代码之前能够进行测试的第一步。
-
我听说#define private public是一个在C ++中激活神模式的作弊码;)
-
我想知道这样的定义是否会破坏二进制兼容性。如果在它们之间存在访问说明符,则编译器(根据标准)可以自由地重新排列类/结构的成员。我想这也适用于访问说明符与之前使用的访问说明符相同。如果编译器根据其访问说明符对成员进行重新排序,并且您不在整个代码中使用#define(外部库也是如此),那么事情可能会中断。
不,这几乎肯定会导致未定义的行为。
来自n4296 17.6.4.3.1 [macro.names] / 2 :(来自下面的@james)
A translation unit shall not #define or #undef names lexically identical to keywords, to the identifiers listed in Table 2, or to the attribute-tokens described in 7.6.
private和public是关键字。如果您在C ++标准库中使用任何内容,那么在其中一个上执行#define是未定义的行为:
17.6.4.1/1 [constraints.overview]
This section describes restrictions on C ++ programs that use the facilities of the C++ standard library.
如果不这样做,17.6.4.3.1中的限制似乎不适用。
另一种可能导致违规的方法是使用具有两种不同定义的相同结构。虽然大多数实现可能并不关心除public vs private之外的两个结构是否相同,但标准并未做出这种保证。
尽管如此,最常见的UB是"它有效",因为很少有编译器在意。
但这并不意味着它"安全"。它在特定的编译器中可能是安全的(检查所述编译器的文档:然而,这将是一个奇怪的保证,但是!)。如果通过两个不同的定义访问相同的结构,很少有编译器(如果有的话)将提供上述所需的布局保证(和修改保证),例如,即使错误的其他可能性更远。
许多编译器都会"正常工作"。这并不能保证安全:下一个编译器版本可以进行无数次更改,并以难以(或简单)检测方式破坏您的代码。
如果收益很大,只做这样的事情。
如果您从不包含任何标准库标头并且不使用它来在两个编译单元中使定义不同,我找不到#define关键字是未定义行为的证据。因此,在高度限制的计划中,它可能是合法的。在实践中,即使它是合法的,它仍然不是"安全的",因为合法性非常脆弱,并且因为编译器不太可能对这种语言滥用进行测试,或者关心它是否会导致错误。
由#define private foo引起的未定义行为似乎不限于在std标头的#include之前执行此操作,作为它是多么脆弱的示例。
-
对不起,但是UB是什么意思?
-
@ user4419862'未定义的行为'
-
@Yakk - 为什么你认为这个案子是UB?什么是c ++规范表明?
-
@Yakk这不能是未定义的行为,macross只处理预处理器,因此在编译预处理器时会将所有私有和受保护更改为public。
-
这将如何导致UB?你的意思是用户的行为? ;-)
-
@DanielSanchez可能不是UB本身(虽然我必须检查)但UB如果影响和标准库头。至于"这不可能是UB ......",如果标准说它是,那就是。
-
是的,我不同意这本身就是UB。它会让人很容易意外地引入UB,但它不是UB本身。
-
@juanchopanza,你在那里得到了一个观点,但任何正在处理私人和受保护的事情也应该对此有所帮助。因此,这取决于用户在这里犯错误。如果他需要访问,他可以用它来编译他需要的任何东西并用作库,或者甚至在完成它时取消它。
-
@Elemental这不是一个建议:"翻译单位不得#define或#undef在词汇上与关键词相同,在表3中列出的标识符,或7.6中描述的属性标记。"
-
@daniel例如,您的编译器可以自由地将private和public实现为预处理器标记。或者取消#define并插入硬盘格式说明。更可能的路线是通过两个不同的定义来获得相同的结构,是真的,但它不是这里唯一的UB类型。
-
@Yakk,你确定这个吗?,据我所知,编译流程是关于这个:预处理器 - >编译器 - >链接器。所以,预处理器会在那里更改标记,然后它将被编译和链接。或者我错了?在这种情况下,那里应该没有问题。
-
@DanielSanchez我从目前的标准草案中引用了一个引文。它明确地描述为那里的未定义行为,这对当前草案来说并不新鲜。特定的编译器工具链可能没有问题,但这是一个标记为C ++的问题,而不是"特定的编译器"。
-
@Yakk,我显然是在谈论C ++编译器。您可以发布您正在谈论的来源吗?我对此很好奇。谢谢 :)
-
@Yakk,刚看到你回答,对不起,谢谢:)
-
@ Yakk-AdamNevraumont,把我的学究帽放在上面,标准没有使用确切的术语"未定义的行为"描述它,它只是声明它是不允许的。如果它是未定义的行为,则不需要编译器诊断它。这里的措辞表明,如果在#include系统头之后#define关键字,编译器应该给出错误的标准。实际上,MSVC在更高版本中就是这样做的。
只允许在不以任何方式(甚至间接)包含标准标题的翻译单元中,但如果您这样做,则存在以下限制:
(17.6.4.3.1) A translation unit shall not #define or #undef names lexically identical to keywords [...]
无论如何,这通常都是一个坏主意 - 使用访问修饰符进行修改对于该词的任何常见含义都不是"安全的",即使它本身不会引起任何直接问题。
如果您正在使用库代码,那么通常有很好的理由来保护它们。
如果您想暂时公开,例如 出于测试目的,您可以为该类的该部分使用特殊的条件宏:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #if TESTING
#define PRIVATE_TESTABLE public
#else
#define PRIVATE_TESTABLE private
#endif
class Foo
{
public:
Foo();
void operation();
PRIVATE_TESTABLE:
int some_internal_operation();
private:
int some_internal_data;
}; |
-
我认为friend class Test_Foo;会更好。
这样做没有任何违法行为,它只是疯了。
您必须对所有编译单元使用此定义(否则,由于名称重整,您可能会使链接器失败。
如果你是出于好奇,那么这是完全合法的(如果令人困惑)c ++;如果你问,因为你认为这是一个好主意,所以你没有所有那些讨厌的访问权限,那么你是一个非常糟糕的道路。使用protected和private有一个特定的语义原因,这有助于降低代码的复杂性并解释模块之间的"契约"。使用此定义会使您的代码几乎无法读取实践的c ++程序员。
-
根据标准,它是未定义的行为,至少如果您使用标准库的任何部分。
语法是正确的,但语义是错误的。
访问修饰符仅适用于人类,因此您不会使用您不应访问/更改的方法或字段等。
如果你编写新代码,你总是可以公开一切,但在旧代码中,它肯定会破坏某些东西。它会工作,但它当然也会更容易出错。想象一下,如果您每次都能访问所有内容,IntelliSense会建议什么。访问修饰符不仅可以保护代码,如果以错误的方式使用它可能会破坏某些内容,但它有助于IntelliSense仅向您显示在特定上下文中相关的成员。