允许访问私有成员(Allowing access to private members)

2019-07-20 15:30发布

这个问题是有点的延续这一个我已经张贴。

我试图做的事 :我的观点是允许访问基类的私有成员A在派生类中B ,具有以下限制:

  • 我要访问是一个结构-一个std::map<>其实- ,不是方法;
  • 不能修改的基类;
  • 基类A没有模板方法我可能超载一个后门替代-我不会增加这样的方法,因为它会被逆着第二约束。

作为一个可能的解决方案,我已经指出litb的解决方案( 后 / 博客 ),但是,对于我的生活,我一直没能达成什么是这些职位做了一个了解,并因此,我可以没有得出一个解决我的问题。

我所试图做的事 :下面的代码,从litb的解决方案,对如何从一个类/结构访问私有成员的方法,它恰好覆盖我提到的限制。

所以,我想重新安排这一个代码:

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的解决方案。

Answer 1:

该博客文章和它的代码是不幸的是有点不清楚。 这个概念很简单:明确模板实例化得到一个免费的后台通行证到任何一类,因为

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

分发该后台通行证的自然的方式是作为指针构件。 如果你有一个指向一个给定的类成员,你可以在这个类的任何对象访问它不管接入资格。 幸运的是,指针到成员可以是编译的时间常数,即使在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;

看看行不行。

不幸的是,你不能从这个是可用于其他源文件全局对象的构造函数依赖于结果的程序进入前main ,因为没有标准的方式来告诉编译器,以便在初始化文件,但是全局在初始化为了他们宣称,所以你可以把你的旁路在顶部,你会没事的,只要静态对象的构造不作函数调用到其他文件。

可靠的版本。

通过增加一个标签结构和借用litb的代码元素friend的功能,但它是一个小的修改,我认为这仍然是很清楚的,不可怕比上面更差。

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;

看看行不行。

这个强大的版本和litb的博客文章之间的主要区别是,我已经收集了所有的参数到一个地方并提出了标签结构空。 这只是一个简洁的界面,以相同的机制。 但是,你必须申报get功能,该博客的代码自动完成。



Answer 2:

好了,你问如何使这一奇怪的“抢”代码您的使用情况下工作,所以在这儿呢。

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

// the class you can't modify
class A {
private:
    std::map<int, int> A_map;
};

struct A_f {
    typedef std::map<int, int> A::*type;
    friend type get(A_f);
};

template struct Rob<A_f, &A::A_map>;

class B : private A {
public:
    inline void uncover() {
        std::map<int, int>::iterator it = (this->*get(A_f())).begin();
    }
};

现在,我个人认为这里的治疗可能比疾病本身更糟糕,尽管我通常是最后一个,你会看到声称滥用C ++就可以了。 你可以自己决定,所以我使用预处理做老派的方式张贴了这个从我的一个单独的答案。

编辑:

这个怎么运作

在这里,我将复制上面的代码,但同类型的简化和绘制的代码更多,用大量的意见。 你要知道,我不明白的代码非常好之前,我通过这个练习去了,我不完全理解,现在它,我肯定不会记得它是如何工作的明天。 需要注意的维护者。

以下是我们不允许改变,与私有成员的代码:

// we can use any type of value, but int is simple
typedef int value_type;

// this structure holds value securely.  we think.
struct FortKnox {
    FortKnox() : value(0) {}
private:
    value_type value;
};

现在的抢劫:

// define a type which is a pointer to the member we want to steal
typedef value_type FortKnox::* stolen_mem_ptr;

// this guy is sort of dumb, but he knows a backdoor in the standard
template<typename AccompliceTag, stolen_mem_ptr MemPtr>
struct Robber {
    friend stolen_mem_ptr steal(AccompliceTag) {
        return MemPtr; // the only reason we exist: to expose the goods
    }
};

// this guy doesn't know how to get the value, but he has a friend who does
struct Accomplice {
    friend stolen_mem_ptr steal(Accomplice);
};

// explicit instantiation ignores private access specifier on value
// we cannot create an object of this type, because the value is inaccessible
// but we can, thanks to the C++ standard, use this value in this specific way
template struct Robber<Accomplice, &FortKnox::value>;

// here we create something based on secure principles, but which is not secure
class FortKnoxFacade : private FortKnox {
public:
    value_type get_value() const {
        // prepare to steal the value
        // this theft can only be perpetrated by using an accomplice
        stolen_mem_ptr accessor = steal(Accomplice()); // it's over now
        // dereference the pointer-to-member, using this as the target
        return this->*accessor;
    }
};

int main() {
    FortKnoxFacade fort;
    return fort.get_value();
}


Answer 3:

怎么样的东西更残酷?

// MY CODE -- module "b.h"
# define private protected
# include <a.h>
# undef private
class B : private A {
    // now you can access "private" members and methods in A


Answer 4:

最好的包装版本,我知道这个成语的情况如下:

template<class Tag,typename Tag::type MemberPtr>
struct access_cast{
 friend typename Tag::type get(Tag){return MemberPtr;};
};

template<class Tag,class MemberPtr>
struct access_tag{
 typedef MemberPtr type;
 friend type get(Tag);
};

class A {
public:
 auto x() const {return x_;};
private: 
 int x_ = 9;
};

#include <iostream>

struct AMemTag: access_tag<AMemTag,int A::*>{}; //declare tag
template struct access_cast<AMemTag,&A::x_>; //define friend get function

int main() {
 A a;
 std::cout<<a.x()<<"\n";
 a.*get(AMemTag()) = 4; //dereference returned member pointer and modify value
 std::cout<<a.x()<<"\n";
}

看看行不行。



文章来源: Allowing access to private members