当前位置:  开发笔记 > 编程语言 > 正文

我可以在不使用朋友的情况下从课外访问私人会员吗?

如何解决《我可以在不使用朋友的情况下从课外访问私人会员吗?》经验,为你挑选了7个好方法。

如果类包含任何模板成员函数,您可以专门化该成员函数以满足您的需要.即使原始开发人员没有想到它.

safe.h

class safe
{
    int money;

public:
    safe()
     : money(1000000)
    {
    }

    template 
    void backdoor()
    {
        // Do some stuff.
    }
};

main.cpp中:

#include 
#include 

class key;

template <>
void safe::backdoor()
{
    // My specialization.
    money -= 100000;
    std::cout << money << "\n";
}

int main()
{
    safe s;
    s.backdoor();
    s.backdoor();
}

输出:

900000
800000

密钥有可能发生冲突.将它放在匿名命名空间中. (14认同)


Johannes Sch.. 54

我在我的博客中添加了一个条目(见下文),展示了如何完成它.以下是如何将其用于以下类的示例

struct A {
private:
  int member;
};

只需为它描述一个结构,然后实例化用于抢劫的实现类

// tag used to access A::member
struct A_member { 
  typedef int A::*type;
  friend type get(A_member);
};

template struct Rob;

int main() {
  A a;
  a.*get(A_member()) = 42; // write 42 to it
  std::cout << "proof: " << a.*get(A_member()) << std::endl;
}

Rob类模板的定义是这样的需要,只有定义一次,不管有多少私有成员计划访问

template
struct Rob { 
  friend typename Tag::type get(Tag) {
    return M;
  }
};

但是,这并未表明c ++的访问规则不可靠.语言规则旨在防止意外错误 - 如果您尝试抢夺对象的数据,则设计语言不会花费很长时间来阻止您.



1> dalle..:

如果类包含任何模板成员函数,您可以专门化该成员函数以满足您的需要.即使原始开发人员没有想到它.

safe.h

class safe
{
    int money;

public:
    safe()
     : money(1000000)
    {
    }

    template 
    void backdoor()
    {
        // Do some stuff.
    }
};

main.cpp中:

#include 
#include 

class key;

template <>
void safe::backdoor()
{
    // My specialization.
    money -= 100000;
    std::cout << money << "\n";
}

int main()
{
    safe s;
    s.backdoor();
    s.backdoor();
}

输出:

900000
800000


密钥有可能发生冲突.将它放在匿名命名空间中.

2> Johannes Sch..:

我在我的博客中添加了一个条目(见下文),展示了如何完成它.以下是如何将其用于以下类的示例

struct A {
private:
  int member;
};

只需为它描述一个结构,然后实例化用于抢劫的实现类

// tag used to access A::member
struct A_member { 
  typedef int A::*type;
  friend type get(A_member);
};

template struct Rob;

int main() {
  A a;
  a.*get(A_member()) = 42; // write 42 to it
  std::cout << "proof: " << a.*get(A_member()) << std::endl;
}

Rob类模板的定义是这样的需要,只有定义一次,不管有多少私有成员计划访问

template
struct Rob { 
  friend typename Tag::type get(Tag) {
    return M;
  }
};

但是,这并未表明c ++的访问规则不可靠.语言规则旨在防止意外错误 - 如果您尝试抢夺对象的数据,则设计语言不会花费很长时间来阻止您.



3> ChrisW..:

以下是偷偷摸摸,非法,依赖编译器,并且可能无法工作,具体取决于各种实现细节.

#define private public
#define class struct

但它是你的OP的答案,你明确地邀请了一种技术,我引用它是"完全愚蠢的,并且任何希望在生产代码中尝试这样的事情的人都应该被解雇和/或开枪".


另一种技术是通过使用来自对象开头的硬编码/手动编码偏移来构造指针来访问私有成员数据.


您还需要#define类struct,否则默认情况下私有可能会阻止您.

4> SmacL..:

嗯,不知道这是否有效,但可能值得一试.创建另一个类,其布局与具有私有成员的对象相同,但私有更改为public.创建指向此类的指针变量.使用简单的强制转换将其指向具有私有成员的对象,并尝试调用私有函数.

期待火花,也许是崩溃;)



5> Rob K..:
class A 
{ 
   int a; 
}
class B
{
   public: 
   int b;
}

union 
{ 
    A a; 
    B b; 
};

应该这样做.

ETA:它适用于这种琐碎的课程,但作为一般情况,它不会.

TC++ PL Section C.8.3:"具有构造函数,析构函数或复制操作的类不能是union成员的类型......因为编译器不知道要销毁哪个成员."

所以我们留下最好的选择是宣布class B匹配A的布局和黑客来看一个班级的私人.



6> Martin York..:

如果您可以获得指向类成员的指针,则无论访问说明符是什么(甚至是方法),都可以使用指针.

class X;
typedef void (X::*METHOD)(int);

class X
{
    private:
       void test(int) {}
    public:
       METHOD getMethod() { return &X::test;}
};

int main()
{
     X      x;
     METHOD m = x.getMethod();

     X     y;
     (y.*m)(5);
}

当然,我最喜欢的小黑客是后门的朋友模板.

class Z
{
    public:
        template
        void backDoor(X const& p);
    private:
        int x;
        int y;
};

假设上面的创建者为他的正常用途定义了backDoor.但是您想要访问该对象并查看私有成员变量.即使将上面的类编译成静态库,您也可以为backDoor添加自己的模板特化,从而访问成员.

namespace
{
    // Make this inside an anonymous namespace so
    // that it does not clash with any real types.
    class Y{};
}
// Now do a template specialization for the method.
template<>
void Z::backDoor(Y const& p)
{
     // I now have access to the private members of Z
}

int main()
{
    Z  z;   // Your object Z

    // Use the Y object to carry the payload into the method.
    z.backDoor(Y());
}



7> JaredPar..:

绝对可以使用C++中的指针偏移来访问私有成员.让我们假设我有以下类型定义,我想访问.

class Bar {
  SomeOtherType _m1;
  int _m2;
};

假设Bar中没有虚拟方法,那么简单的情况就是_m1.C++中的成员存储为对象的内存位置的偏移量.第一个对象位于偏移0处,第二个对象位于sizeof(第一个成员)的偏移处,等等...

所以这是一种访问_m1的方法.

SomeOtherType& GetM1(Bar* pBar) {
  return*(reinterpret_cast(pBar)); 
}

现在_m2有点困难了.我们需要从原始字节移动原始指针sizeof(SomeOtherType)字节.转换为char是为了确保我以字节偏移量递增

int& GetM2(Bar* pBar) {
  char* p = reinterpret_cast(pBar);
  p += sizeof(SomeOtherType);
  return *(reinterpret_cast(p));
}

推荐阅读
sx-March23
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有