C++ 访问类私有成员变量

2026-06-30 01:30:01

首先介绍一下类的数据成员指针。当对类的数据成员执行取址操作时,可以获得类的数据成员指针。本质上是附带类型信息的地址偏移。这部分可以参考文献 1。

#include

#include

#include

struct A {

int x;

int y;

double z;

};

int main() {

int A::*a = &A::x; // a 的类型为 `int A::*`

int A::*b = &A::y;

double A::*c = &A::z;

A o;

o.*a = 10; // 可以使用 obj.* 运算符访问

o.*(&A::y) = 20;

assert(o.x == 10);

assert(o.y == 20);

a = b; // 同类型可以赋值,本质上是地址偏移

assert(sizeof(a) == sizeof(void *)); // 与指针大小一致

assert(*(uintptr_t *)(&a) == 4); // 偏移量为 4

*(uintptr_t *)(&a) = 0; // 也就可以强行修改值了

assert(o.*a == 10); // 偏移量为 0 时会访问 A::x

}

那么如果有类私有数据成员指针,就可以访问对应的私有变量了,但 C++ 并不允许直接对类私有成员取址:

#include

#include

#include

class A {

public:

int X() { return x_; }

int Y() { return y_; }

private:

int x_;

int y_;

};

int main() {

A o;

int A::*a;

*(uintptr_t *)(&a) = 0;

o.*a = 10;

assert(o.X() == 10);

*(uintptr_t *)(&a) = 4;

o.*a = 20;

assert(o.Y() == 20);

// a = &A::x_; // not allowed

}

幸运的是 C++ 模版类的显式实例化会忽略成员访问说明符,参考文献 3:

Explicit instantiation definitions ignore member access specifiers: parameter types and return types may be private.

这也就允许传入类私有成员变量地址。如此设计的原因暂不得知,但利用该规则就可以实现访问任意类的私有成员变量:

#include

#include

class A {

public:

int X() { return x_; }

private:

int x_;

};

int A::*FiledPtr();

template

struct Rob {

friend int A::*FiledPtr() { return M; }

};

template struct Rob<&A::x_>;

int main() {

A o;

o.*FiledPtr() = 10;

assert(o.X() == 10);

}

说它是奇技淫巧不为过,但某些场景下确实需要这样的黑科技。例如 folly 库中实现的 atomic_shared_ptr,就需要访问标准库 std::shared_ptr 的私有引用计数成员进行计数的修改。

这种方法还是需要定义几个辅助类,如果想访问标准库中的类私有成员,有没有更简单、直接的技巧呢?有的 :D

#include

#define private public

#include

#undef private

int main() {

std::shared_ptr a;

a._M_refcount; // gcc, access private member

}

宏替换 private 并不总是有效,不建议在实际项目中使用,仅适用于单元测试场景。实际项目中可以使用 access_private,其头文件中定义了一些访问私有成员 / 函数的宏,原理仍然是模版类显式实例化:

#include

#include "access_private.hpp"

class A {

int m_i = 3;

};

ACCESS_PRIVATE_FIELD(A, int, m_i)

void foo() {

A a;

auto &i = access_private::m_i(a);

assert(i == 3);

}

References

"Pointers to data members", C++ Reference

"Member access operators", C++ Reference

"Explicit instantiation", C++ Reference

Copyright © 2022 游戏活动大全网 - 全网活动一网打尽 All Rights Reserved.