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

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

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

问题

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

class X
{
private:
   class A
   {...};
   std::vector<A> arr;
};

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

class X
{
private:
	int a;
};

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

struct X_A
{ 
	typedef int X::* type;
	friend type get(X_A);
};

template struct XAccessor<X_A, &X::a>;

// ...
auto x = new X;
(*x).*get(X_A()) = 11;
// ...

我在网上找到了这种方法,但是当我将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

class X
{
private:
   class A
   {...};
   vector&lt;A&gt; arr;
}

Q:How can I access X::arr ?

class X
{
private:
	int a;
};

template&lt;typename Tag, typename Tag::type Member&gt;
struct XAccessor 
{ 
	friend typename Tag::type get(Tag) 
	{
		return Member;
	} 
};

struct X_A
{ 
	typedef int X::* type;
	friend type get(X_A);
};;

template struct XAccessor&lt;X_A, &amp;X::a&gt;;

...
auto x = new X;
x-&gt;*get(X_A())=11;
...

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

// 以下三个声明为我们提供了对 X::a 的数据成员指针
auto steal();

template <auto Ptr>
struct Thief {
    friend auto steal() {
        return Ptr;
    }
};

// 显式实例化 Thief<&X::a>
template struct Thief<&X::a>;

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

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

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

// 可以从数据成员指针中提取 Hidden 的特征
template <typename T>
struct member_type;

template <typename C, typename M>
struct member_type<M C::*&gt; {
    using type = M;
};

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

// X_Hidden = X::Hidden
using X_Hidden = member_type<decltype(steal())>::type;

// 在运行时窃取私有数据成员
X_Hidden get_a(const X &x) {
    X_Hidden X::*a = steal();
    return x.*a;
}

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;.

class X
{
private:
    struct Hidden {};
    Hidden a;
};

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

// the following three declarations give us a data member pointer to X::a
auto steal();

template &lt;auto Ptr&gt;
struct Thief {
    friend auto steal() {
        return Ptr;
    }
};

// explicit instantiation of specialization Thief&lt;&amp;X::a&gt;
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:

// trait which lets us extract Hidden from a data member pointer
template &lt;typename T&gt;
struct member_type;

template &lt;typename C, typename M&gt;
struct member_type&lt;M C::*&gt; {
    using type = M;
};

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

// X_Hidden = X::Hidden
using X_Hidden = member_type&lt;decltype(steal())&gt;::type;

// steal private data member at runtime
X_Hidden get_a(const X &amp;x) {
    X_Hidden X::*a = steal();
    return x.*a;
}

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:

确定