为什么“#if !(protected) and !(private)”不能防御“#define private public”?

why "#if !(protected) and !(private)" cannot defense "#define private public"?

我尝试一些方法来防止有人像这样强制私有 public:

#define private public
#if !(protected) and !(private)
#define A 1
#endif
class B{
private:
    int c;
};
int main(){
    int a=A;
    B b;
    b.c=2;
};

一开始我认为这段代码无法编译因为

#define private public

会触发

#if !(protected) and !(private)

防止A定义。但实际上这段代码是可以编译的,同时我可以直接访问B的private成员,也就是说private已经变成了public。但是为什么A还能定义?

您永远不应该 #define 关键字,例如 private。如果您从同一个 .cpp 文件中包含标准库的任何部分(甚至是 <new><initializer_list> 等基本语言功能所需的部分),则行为未定义。

也就是说,当 #if 对其表达式求值时,任何标识符或关键字标记都被视为数字零。解读如下:

  1. #if !(protected) and !(private)
  2. #if !(protected) and !(public)
  3. #if !(0) and !(0)
  4. #if true

您可能正在寻找 defined 运算符,它会告诉您其操作数是否为宏。

#if ! defined(protected) and ! defined(private)

不过,还是不要这样做。


如果您的目标是防止某人盗用关键字,可以这样做:

#if defined(protected) || defined(private) || …
#   error Do not hack keywords!
#endif

这对于防御性编码来说太过分了。 C++ 并没有真正为您提供弹药来防止用户入侵您的库。不遵守规则的用户会在伤害你之前先伤害自己……只需明确表示不支持古怪的程序即可。即使那样也应该是不必要的,不用说。

#if !(protected) and !(private)

在预处理阶段进行评估。在此阶段,protected 和 private 被视为预处理标记,而不是关键字。 private 被替换为 public,因为您已经这样定义了它。然后将 protected 和 public 的实例替换为 0,因为一旦完成所有宏替换,所有剩余的标识符将始终替换为 0。所以这些行变为

#if !(0) and !(0)
    #define A 1
#endif

其中大部分内容的详细信息可以在 C99 的 6.10.1 第 4 段和 C++11 的 16.1 第 4 段中找到。

privateprotectedpublic 部分旨在防止意外滥用。它们不能用于防止故意滥用。

用户更改很简单

class B{
  private:
    int c;
};

class B{
  public:
    int c;
};

class B{
  private:
    friend class UserClass;
    int c;
};

以访问 B 的私人部分。

不要在这些事情上浪费精力