【问题标题】:Define private to public in C++ [duplicate]在C ++中定义私有到公共[重复]
【发布时间】:2015-01-05 11:48:33
【问题描述】:

我想定义私有和受保护的公共。

#define private public
#define protected public

这在 C++ 中安全吗?

【问题讨论】:

  • 你为什么要那个?它可能不会改变程序的运行时行为,但会禁用许多非常有用的编译器诊断。显示让你想要这样做的代码!
  • 但这很有趣。
  • 您可能有无法解析的符号,因为名称修改可以使用可见性。
  • #define TRUE FALSE一样不安全

标签: c++


【解决方案1】:

不,这几乎肯定会导致未定义的行为。

来自n4296 17.6.4.3.1 [macro.names] /2:(通过下面的@james)

翻译单元不得#define#undef 名称在词法上与关键字、表 2 中列出的标识符或 7.6 中描述的属性标记相同。

privatepublic 是关键字。只需在其中一个上执行#define 就是未定义的行为如果您使用 C++ 标准库中的任何内容:

17.6.4.1/1 [constraints.overview]

本节描述了对使用 C++ 标准库设施的 C++ 程序的限制。

如果不这样做,则 17.6.4.3.1 中的限制似乎不适用。

可能导致违规的另一种方式是,如果您使用具有两个不同定义的相同结构。尽管除了publicprivate 之外,大多数实现可能并不关心这两个结构是否相同,但标准并没有做出这样的保证。

尽管如此,最常见的 UB 是“它可以工作”,因为很少有编译器关心。

但这并不意味着它是“安全的”。在特定的编译器中它可能是安全的(检查所述编译器的文档:但是,这将是一个奇怪的保证!)。如果您通过两个不同的定义访问相同的结构,例如,即使其他错误的可能性更小,很少有编译器(如果有的话)会提供上述工作所需的布局保证(和修饰保证)。

许多编译器将“正常工作”。这并不保证安全:下一个编译器版本可能会进行无数更改,并以难以(或容易)检测的方式破坏您的代码。

只有在收益很大时才做这样的事情。

如果您从不包含任何标准库头文件并且不使用它在两个编译单元中进行不同的定义,我无法找到#defineing 关键字是未定义行为的证据。所以在一个高度受限的程序中,它可能是合法的。在实践中,即使它是合法的,它仍然不是“安全的”,因为这种合法性非常脆弱,而且编译器不太可能针对这种语言滥用进行测试,或者关心它是否会导致错误。

#define private foo 引起的未定义行为似乎并不局限于在std 标头的#include 之前执行此操作,例如它是多么脆弱。 p>

【讨论】:

  • 对不起,UB 是什么意思?
  • @user4419862 '未定义的行为'
  • @Yakk - 为什么你认为这个案例是 UB? c++ 规范表明了什么?
  • @Yakk 这不能是未定义的行为,宏仅处理预处理器,因此在编译预处理器时会将所有私有和保护更改为公共。
  • @DanielSanchez 可能不是 UB 本身(尽管我必须检查一下),但 UB 是否会影响标准库头文件。至于“这不可能是UB……”,如果标准说是,那就是。
【解决方案2】:

仅允许在不以任何方式(甚至间接)包含标准标题的翻译单元中,但如果您这样做,则存在以下限制:

(17.6.4.3.1) 翻译单元不得#define 或#undef 名称在词法上与关键字相同[...]

不管怎样,这通常是个坏主意 - 使用访问修饰符在该词的任何常见含义上都不是“安全”的,即使它本身不会引起任何直接问题。
如果您使用库代码,通常有充分的理由保护事物。

如果您想暂时公开某些内容,例如出于测试目的,您可以对类的该部分使用特殊的条件宏:

#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; 我认为会更好。
  • 我喜欢这个想法,但我遇到了类似 `error C2334: unexpected token(s) before ':'; 之类的错误。跳过明显的函数体`,因为它不知道如何处理PRIVATE_TESTABLE
【解决方案3】:

这样做并没有什么违法的,只是太疯狂了。

您必须对所有编译单元使用此定义(否则您可能会因为名称重整而导致链接器失败。

如果您是出于好奇而询问,那么这是完全合法的(如果令人困惑)c++;如果您之所以问,是因为您认为这是一个好主意,因此您没有所有那些讨厌的访问权限,那么您就走上了一条非常糟糕的道路。使用 protected 和 private 有一个特定的语义原因,这有助于降低代码的复杂性并解释模块之间的“契约”。使用这个定义会让你的代码对于熟练的 C++ 程序员来说几乎是不可读的。

【讨论】:

  • 根据标准,这是未定义的行为,至少如果您使用标准库的任何部分。
【解决方案4】:

语法正确,但语义错误。

【讨论】:

    【解决方案5】:

    访问修饰符仅适用于人类,因此您不会意外使用您不应该访问/更改的方法或字段等。

    如果您编写新代码,您也可以始终公开所有内容,但在旧代码中它肯定会破坏某些内容。它会起作用,但它当然也更容易出错。想象一下IntelliSense 如果您每次都可以访问所有内容会提出什么建议。访问修饰符不仅可以保护如果您以错误的方式使用它可能会破坏某些内容的代码,而且它有助于IntelliSense 仅向您显示与特定上下文相关的成员。

    【讨论】:

      猜你喜欢
      • 2014-09-21
      • 1970-01-01
      • 2013-08-09
      • 2013-09-02
      • 2013-01-31
      • 2016-11-24
      • 2014-02-01
      • 2019-08-26
      • 2011-09-17
      相关资源
      最近更新 更多