gpt4 book ai didi

c++ - 允许访问私有(private)成员

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:57:58 24 4
gpt4 key购买 nike

这个问题在某种程度上是 this one 的延续我已经发布了。

我想做的:我的意思是允许访问基类的私有(private)成员 A在派生类中 B , 具有以下限制:

  • 我想访问的是一个结构 -- std::map<> ,实际上——,不是一种方法;
  • 不能修改基类;
  • 基类 A没有模板化的方法,我可以作为后门替代方案重载——我不会添加这样的方法,因为它会反对第二个约束。

作为一个可能的解决方案,有人指出我是 litb 的解决方案 ( post/blog ),但是,对于我来说,我一直无法理解这些帖子中所做的事情,因此,我无法得出解决问题的方法。

我正在尝试做的事情:以下代码来自 litb 的解决方案,提供了一种如何从类/结构访问私有(private)成员的方法,它恰好涵盖了我的限制提到。

所以,我正在尝试重新排列这段代码:

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

对于允许我执行以下操作的内容 -- 请注意,我将继承该类,因为 std::map<> 中的条目在派生类初始化后立即添加 B ,即 std::map<>不仅仅是类 A 的静态成员具有默认值,因此我需要从 B 的特定实例访问它:

// NOT MY CODE -- library <a.h>
class A {
private:
std::map<int, int> A_map;
};

// MY CODE -- module "b.h"
# include <a.h>
class B : private A {
public:
inline void uncover() {
for (auto it(A_map.begin()); it != A_map.end(); ++it) {
std::cout << it->first << " - " << it->second << std::endl;
}
}
};

我想要的答案:我真的喜欢让上面的代码工作——在适当的修改之后——但我会非常对第一个代码块(来自 litb 的解决方案)中所做的解释感到满意。

最佳答案

不幸的是,博文及其代码有点不清楚。这个概念很简单:显式模板实例化可以免费获得任何类的后台通行证,因为

  • 库类的显式实例化可能是客户端类的实现细节,并且
  • 显式实例化只能在命名空间范围内声明。

分发此后台通行证的自然方式是作为指向成员的指针。如果您有一个指向给定类成员的指针,则可以在该类的任何对象中访问它,而不管访问资格如何。幸运的是,即使在 C++03 中,指向成员的指针也可以是编译时常量。

因此,我们需要一个在显式实例化时生成指向成员的指针的类。

显式实例化只是定义类的一种方式。仅生成一个类如何某事?有两种选择:

  • 定义一个 friend 函数,它不是类的成员。这就是 litb 所做的。
  • 定义一个静态数据成员,它在启动时被初始化。这是我的风格。

我会先介绍我的风格,然后讨论它的缺点,然后修改它以匹配 litb 的机制。最终结果仍然比博客中的代码简单。

简单版。

该类采用三个模板参数:受限成员的类型、其实际名称以及对全局变量的引用以接收指向它的指针。该类调度一个要初始化的静态对象,其构造函数初始化全局对象。

template< typename type, type value, type & receiver >
class access_bypass {
static struct mover {
mover()
{ receiver = value; }
} m;
};

template< typename type, type value, type & receiver >
typename access_bypass< type, value, receiver >::mover
access_bypass< type, value, receiver >::m;

用法:

type_of_private_member target::* backstage_pass;
template class access_bypass <
type_of_private_member target::*,
& target::member_name,
backstage_pass
>;

target t;
t.* backstage_pass = blah;

See it work.

不幸的是,在程序进入 main 之前,您不能依赖此结果可用于其他源文件中的全局对象构造函数,因为没有标准方法告诉编译器哪个顺序初始化文件。但是全局变量是按照它们声明的顺序初始化的,所以你可以把你的旁路放在顶部,只要静态对象构造函数不对其他文件进行函数调用就可以了。

健壮的版本。

通过添加标签结构和friend 函数,这从 litb 的代码中借用了一个元素,但这是一个很小的修改,我认为它仍然很清楚,并不比上面的差很多。

template< typename type, type value, typename tag >
class access_bypass {
friend type get( tag )
{ return value; }
};

用法:

struct backstage_pass {}; // now this is a dummy structure, not an object!
type_of_private_member target::* get( backstage_pass ); // declare fn to call

// Explicitly instantiating the class generates the fn declared above.
template class access_bypass <
type_of_private_member target::*,
& target::member_name,
backstage_pass
>;

target t;
t.* get( backstage_pass() ) = blah;

See it work.

这个健壮的版本和 litb 的博客文章之间的主要区别在于我将所有参数收集到一个地方并使标签结构为空。它只是对相同机制的更清晰的接口(interface)。但是您必须声明 get 函数,博客代码会自动执行此操作。

关于c++ - 允许访问私有(private)成员,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15110526/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com