指向成员的指针是否绕过成员的访问级别?

时间:2012-03-28 12:18:12

标签: c++ c++11 standards-compliance

我们臭名昭着的litb在how to circumvent the access check上有一篇有趣的文章。

这个简单的代码充分证明了这一点:

#include <iostream>

template<typename Tag, typename Tag::type M>
struct Rob { 
  friend typename Tag::type get(Tag) {
    return M;
  }
};

// use
struct A {
  A(int a):a(a) { }
private:
  int a;
};

// tag used to access A::a
struct A_f { 
  typedef int A::*type;
  friend type get(A_f);
};

template struct Rob<A_f, &A::a>;

int main() {
  A a(42);
  std::cout << "proof: " << a.*get(A_f()) << std::endl;
}

使用gcc 4.3.4gcc 4.5.1,gcc 4.7.0编译并运行(输出42)(请参阅user1131467&#39;评论)并使用Clang 3.0和Comeau C /进行编译C ++ 4.3.10.1在 C ++ 03严格模式和MSVC 2005中。

Luchian在this answer上问过我,我用它来证明它实际上是合法的。我同意Luchian的观点,这很奇怪,但是Clang和Comeau都是最具竞争力的竞争对手#34; Standard&#34;编译器可用(默认情况下比MSVC更多)......

我在标准草案中找不到任何内容(n3337是我得到的最后一个版本)。

那么......任何人都能证明它是合法还是不

2 个答案:

答案 0 :(得分:13)

是的,这是合法的。相关文本见§14.7.2/ 12,讨论了显式模板实例化:

  

12通常的访问检查规则不适用于用于指定显式实例化的名称。 [注意:特别是,函数声明符中使用的模板参数和名称(包括参数类型,返回类型和异常规范)可能是通常无法访问的私有类型或对象,模板可能是一个成员模板或成员函数,通常不会   无障碍。 - 结束记录]

Emhpasis mine。

答案 1 :(得分:5)

代码显然是非法的(并且需要编译时诊断)。 在该行:

template struct Rob<A_f, &A::a>;

表达式A::a访问A的私有成员。

标准非常明确:“应用访问控制 统一到所有名称,无论是否引用名称 声明或表达。“(§11/ 4,重点补充)。由于aA中的私人名称,因此在A之外对其进行的任何引用都是非法的。