如何访问C++中私有类型的私有成员?

huangapple go评论106阅读模式
英文:

How to access private members of a private type in C++?

问题

要访问私有成员而不修改.h文件,您可以使用以下示例中的代码:

  1. class X
  2. {
  3. private:
  4. class A
  5. {...};
  6. std::vector<A> arr;
  7. };

问题:如何访问X::arr?

  1. class X
  2. {
  3. private:
  4. int a;
  5. };
  6. template<typename Tag, typename Tag::type Member>
  7. struct XAccessor
  8. {
  9. friend typename Tag::type get(Tag)
  10. {
  11. return Member;
  12. }
  13. };
  14. struct X_A
  15. {
  16. typedef int X::* type;
  17. friend type get(X_A);
  18. };
  19. template struct XAccessor<X_A, &X::a>;
  20. // ...
  21. auto x = new X;
  22. (*x).*get(X_A()) = 11;
  23. // ...

我在网上找到了这种方法,但是当我将typedef int X::* type更改为typedef std::vector<X::A> X::* type时,它会报错,说X::A不可访问。

英文:

I want to access private members without modifying the .h file.
This is an example of a .h file

  1. class X
  2. {
  3. private:
  4. class A
  5. {...};
  6. vector&lt;A&gt; arr;
  7. }

Q:How can I access X::arr ?

  1. class X
  2. {
  3. private:
  4. int a;
  5. };
  6. template&lt;typename Tag, typename Tag::type Member&gt;
  7. struct XAccessor
  8. {
  9. friend typename Tag::type get(Tag)
  10. {
  11. return Member;
  12. }
  13. };
  14. struct X_A
  15. {
  16. typedef int X::* type;
  17. friend type get(X_A);
  18. };;
  19. template struct XAccessor&lt;X_A, &amp;X::a&gt;;
  20. ...
  21. auto x = new X;
  22. x-&gt;*get(X_A())=11;
  23. ...

I found this approach online, but when I changed typedef int X::* type to typedef vector&lt;X::A&gt; X::* type, it gave me an error saying that X::A is not accessible.

答案1

得分: 8

如果你能窃取数据成员指针,你可以从中提取类型。以下是一个解决方案,对原始的 X 没有进行任何修改。

假设我们有一个无法修改的类 X,其中包含一个私有数据成员,类型为私有类型 Hidden。在你的示例中,Hidden = std::vector<A>

我们可以创建一个函数,返回数据成员指针 X::*a,而无需命名类型为 X::Hidden

  1. // 以下三个声明为我们提供了对 X::a 的数据成员指针
  2. auto steal();
  3. template <auto Ptr>
  4. struct Thief {
  5. friend auto steal() {
  6. return Ptr;
  7. }
  8. };
  9. // 显式实例化 Thief<&X::a>
  10. template struct Thief<&X::a>;

之所以这样做有效,是因为当显式实例化模板时,成员访问限制被禁用,因此 Thief<&X::a> 不会导致编译失败。这是有意设计的,否则你将无法显式实例化涉及非公有成员的任何模板。

Thief 定义了一个隐藏的友元函数 steal(),它返回数据成员指针,并充当封装的“越狱”功能。steal() 只是一个自由函数,并不包含 &X::aX::Hidden 在任何模板参数或函数参数中,因此没有限制我们对它的访问。

我们还创建了一个类型特征,以便从该指针中提取数据类型:

  1. // 可以从数据成员指针中提取 Hidden 的特征
  2. template <typename T>
  3. struct member_type;
  4. template <typename C, typename M>
  5. struct member_type<M C::*&gt; {
  6. using type = M;
  7. };

最后,我们能够访问私有类型 X::Hidden 和私有数据成员 X::a

  1. // X_Hidden = X::Hidden
  2. using X_Hidden = member_type<decltype(steal())>::type;
  3. // 在运行时窃取私有数据成员
  4. X_Hidden get_a(const X &x) {
  5. X_Hidden X::*a = steal();
  6. return x.*a;
  7. }

Compiler Explorer 上查看实际演示

英文:

If you can steal the data member pointer, you can extract the type from it. Here is a solution that works with zero modifications to the original X.

Say we have a class X which we can't modify, containing a private data member of private type Hidden. In your example, Hidden = std::vector&lt;A&gt;.

  1. class X
  2. {
  3. private:
  4. struct Hidden {};
  5. Hidden a;
  6. };

We can create a function that returns the data member pointer X::*a, without naming the type X::Hidden:

  1. // the following three declarations give us a data member pointer to X::a
  2. auto steal();
  3. template &lt;auto Ptr&gt;
  4. struct Thief {
  5. friend auto steal() {
  6. return Ptr;
  7. }
  8. };
  9. // explicit instantiation of specialization Thief&lt;&amp;X::a&gt;
  10. template struct Thief&lt;&amp;X::a&gt;;

The reason why this works is that member access restrictions are disabled when explicitly instantiating templates, so Thief&lt;&amp;X::a&gt; will not fail to compile.
This is intentional design, because otherwise you would be unable to explicitly instantiate any templates involving non-public members.

Thief defines a hidden friend steal(), which returns the data member pointer, and acts as a "jailbreak" for encapsulation.
steal() is just a free function, and doesn't contain &amp;X::a or X::Hidden in any template parameters or function parameters, so nothing restricts our access to it.

We also create a type trait so we can extract the data type from this pointer:

  1. // trait which lets us extract Hidden from a data member pointer
  2. template &lt;typename T&gt;
  3. struct member_type;
  4. template &lt;typename C, typename M&gt;
  5. struct member_type&lt;M C::*&gt; {
  6. using type = M;
  7. };

Finally, we are able to access both the private type X::Hidden, and the private data member X::a:

  1. // X_Hidden = X::Hidden
  2. using X_Hidden = member_type&lt;decltype(steal())&gt;::type;
  3. // steal private data member at runtime
  4. X_Hidden get_a(const X &amp;x) {
  5. X_Hidden X::*a = steal();
  6. return x.*a;
  7. }

See live demo on Compiler Explorer.

答案2

得分: -5

在C++中,私有成员被故意隐藏,不能直接从类外部访问。封装的概念确保类的内部实现细节不会暴露给外部实体。

英文:

In C++, private members are intentionally hidden and cannot be accessed directly from outside the class. The concept of encapsulation ensures that the internal implementation details of a class are not exposed to external entities.

huangapple
  • 本文由 发表于 2023年6月18日 23:39:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/76501315.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定