允许访问私人成员 [英] Allowing access to private members

查看:98
本文介绍了允许访问私人成员的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题有时是这一个的延续。已发布。



我想做的:我的观点是允许访问基类的私有成员 A 中的 $ b

  • 我想要访问的是一个结构 - std :: map<> ,实际上不是方法;

  • 不能修改基类;

  • 基类没有模板方法我可能超载作为一个后门的选择 - 我不会添加这样的方法,因为它会对第二个约束。



  • 作为一种可能的解决方案,我指向litb的解决方案( post / blog ),但是,对于我的生活,我没有能力以了解这些职位所做的工作,因此,我无法推导出解决我的问题。



    我想做什么:以下代码,来自litb的解决方案,介绍了如何从类/结构访问私有成员的方法,它恰好涵盖了我提到的限制。



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

      template< typename Tag,typename Tag ::类型M> 
    struct Rob {
    friend typename Tag :: type get(Tag){
    return M;
    }
    };

    //使用
    struct A {
    A(int a):a(a){}
    private:
    int a;
    };

    //用于访问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>一张地图;
    };

    //我的代码 - 模块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<第一<< - <<第二<< std :: endl;
    }
    }
    };

    我想要的答案:我真的 love 让上面的代码工作 - 在适当的修改后,但我会非常内容与第一个代码块中做什么的解释 - 一个来自litb的解决方案。

    解决方案

    博客文章和它的代码是不幸的是有点不清楚。这个概念很简单:显式的模板实例化将一个免费的后台传递给任何类,因为




    • 客户类的实现细节和

    • 显式实例化只能在命名空间范围内声明。



    分发这个后台传递的自然方式是作为指向成员的指针。如果你有一个指向给定类成员的指针,你可以在该类的任何对象中访问它,而不管访问限制。幸运的是,指向成员的指针可以是编译时常量,即使在C ++ 03中。



    因此,我们需要一个类,实例化。



    显式实例化只是一种定义类的方法。如何只是产生一个类的东西?有两种选择:




    • 定义 friend 函数,它不是成员的类。这是litb的作用。

    • 定义一个静态数据成员,它在启动时被初始化。这是我的风格。



    我先介绍我的风格,然后讨论它的缺点,然后修改它以匹配litb的机制。



    简单版本。



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

      template<类型名类型,类型值,类型&接收机> 
    class access_bypass {
    static struct mover {
    mover()
    {receiver = value; }
    } m;
    };

    template<类型名类型,类型值,类型&接收机>
    typename access_bypass< type,value,receiver> :: mover
    access_bypass< type,value,receiver> :: m;

    用法:

     code> type_of_private_member target :: * backstage_pass; 
    模板类access_bypass<
    type_of_private_member target :: *,
    & target :: member_name,
    backstage_pass
    > ;;

    target t;
    t。* backstage_pass = blah;

    查看工作。 / a>



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



    稳健的版本。



    这通过添加一个标签结构和一个朋友函数从litb的代码中借用一个元素,但它是一个小修改,我认为它仍然很清楚,不会比

     模板<类型名类型,类型值,类型名标签> 
    class access_bypass {
    friend type get(tag)
    {return value; }
    };

    用法:

     code> struct backstage_pass {}; //现在这是一个虚拟结构,而不是一个对象! 
    type_of_private_member target :: * get(backstage_pass); // declare fn to call

    //显式实例化类生成上面声明的fn。
    模板类access_bypass<
    type_of_private_member target :: *,
    & target :: member_name,
    backstage_pass
    > ;;

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

    工作原理。 / a>



    这个强大的版本和litb的博客文章的主要区别是我已经将所有的参数收集到一个地方,并使标签结构为空。它只是一个更清洁的接口相同的机制。但你必须声明 get 函数,博客代码会自动执行。


    This question is somewhat a continuation of this one I've posted.

    What I was trying to do: my point was to allow access to private members of a base class A in a derived class B, with the following restraints:

    • what I want to access is a structure -- an std::map<>, actually --, not a method;
    • I cannot modified the base class;
    • base class A has no templated method I may overload as a backdoor alternative -- and I would not add such method, as it would be going against the second restraint.

    As a possible solution, I have been pointed to litb's solution (post / blog), but, for the life of me, I haven't been able to reach an understanding on what is done in these posts, and, therefore, I could not derive a solution to my problem.

    What I am trying to do: The following code, from litb's solution, presents an approach on how to access private members from a class/struct, and it happens to cover the restrictions I've mentioned.

    So, I'm trying to rearrange this one code:

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

    To something that would allow me to do the following -- note I'm about to inherit the class, as the entries in the std::map<> are added right after the initialization of the derived class B, i.e., the std::map<> isn't simply a static member of class A with a default value, so I need to access it from a particular instance of 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;
            }
        }
    };
    

    What I'd like as an answer: I'd really love to have the above code working -- after the appropriate modifications --, but I'd be very content with an explanation on what is done in the first code block -- the one from litb's solution.

    解决方案

    The blog post and its code is unfortunately a bit unclear. The concept is simple: an explicit template instantiation gets a free backstage pass to any class, because

    • An explicit instantiation of a library class may be an implementation detail of a client class, and
    • Explicit instantiations may only be declared at namespace scope.

    The natural way to distribute this backstage pass is as a pointer to member. If you have a pointer to a given class member, you can access it in any object of that class regardless of the access qualification. Fortunately, pointer-to-members can be compile-time constants even in C++03.

    So, we want a class which generates a pointer to member when it's explicitly instantiated.

    Explicit instantiation is just a way of defining a class. How can merely generating a class do something? There are two alternatives:

    • Define a friend function, which is not a member of the class. This is what litb does.
    • Define a static data member, which gets initialized at startup. This is my style.

    I'll present my style first, then discuss its shortcoming, and then modify it to match litb's mechanism. The end result is still simpler than the code from the blog.

    Simple version.

    The class takes three template arguments: the type of the restricted member, its actual name, and a reference to a global variable to receive a pointer to it. The class schedules a static object to be initialized, whose constructor initializes the global.

    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;
    

    Usage:

    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.

    Unfortunately, you can't rely on results from this being available for global-object constructors in other source files before the program enters main, because there's no standard way to tell the compiler which order to initialize files in. But globals are initialized in the order they're declared, so you can just put your bypasses at the top and you'll be fine as long as static object constructors don't make function calls into other files.

    Robust version.

    This borrows an element from litb's code by adding a tag structure and a friend function, but it's a minor modification and I think it remains pretty clear, not terribly worse than the above.

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

    Usage:

    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.

    The main difference between this robust version and litb's blog post is that I've collected all the parameters into one place and made the tag structure empty. It's just a cleaner interface to the same mechanism. But you do have to declare the get function, which the blog code does automatically.

    这篇关于允许访问私人成员的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆