You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++访问类私有成员时友元函数get的声明作用及访问规则疑问

C++私有成员访问技巧:友元函数可见性解析

先看这段用于访问类私有成员的C++代码:

#include <iostream>

struct A {
private:
  int member;
};

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

// 用于访问A::member的标签结构体
struct A_member { 
  typedef int A::*type;
  friend type get(A_member);
};

template struct Rob<A_member, &A::member>;

int main() {
  A a;
  a.*(get(A_member())) = 42; // 向私有成员写入42
  std::cout << "proof: " << a.*get(A_member()) << std::endl;
}

核心疑问

按照cppreference的说明,Rob结构体的显式实例化已经把get函数定义为全局命名空间的非成员函数,为什么main里直接访问不到?移除A_member中的friend type get(A_member);声明后编译报错,这个声明到底起什么作用?

关键原理:C++友元函数的名称查找规则

这里的核心是友元函数的可见性规则和依赖于参数的查找(ADL):

  • 当在模板结构体Rob内部定义friend get函数时,虽然这个函数最终是全局命名空间的非成员函数,但它的名称不会自动进入全局命名空间的普通查找范围——友元函数的定义不会主动把名称“暴露”到外围命名空间,除非有对应的外部声明。
  • A_member里的friend type get(A_member);声明,是给ADL留的“入口”:
    • 它在A_member的作用域内声明了get函数的存在;
    • 当main里调用get(A_member())时,因为传入的参数是A_member类型,编译器会触发ADL——自动去参数类型的作用域里查找匹配的函数声明,从而找到那个由Rob显式实例化生成的全局get函数。
  • 如果移除这个友元声明,main里调用get时,普通全局查找找不到它,ADL也找不到对应的函数声明,编译器自然会报错说get未定义。

这个技巧本质是利用了:模板显式实例化会强制生成友元函数的定义,加上ADL的特性,绕开了私有成员的访问限制——而那个友元声明就是让外部代码能通过ADL找到这个“隐藏”的全局友元函数的关键。

内容的提问来源于stack exchange,提问作者Monte

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 10:53:20