在创建结构时修改的类私有成员(C ++)

时间:2010-09-29 09:37:53

标签: c++ oop class reinterpret-cast

我刚刚浏览了一些C ++代码。 在哪里我遇到了reinterpret_cast运算符的概念。

编辑1:

我知道不建议访问班级的私人成员。 但在某些情况下,我们应该继续访问它们。 我刚提出这个问题,以明确我的观点。

在我提到的示例中,通过简单地创建具有相同变量的结构来访问类的私有成员,然后通过实现修改 reinterpret_cast运营商。

我已经理解了reinterpret_cast运算符的用法,就像我知道那样,但我无法理解如何结构可用于修改私有类成员的值。

以下是我提到的源代码:

类别:

class Student
{
public:
    explicit Student(float percent) // Cannot be used for conversion
    {
        static int nid;

        id = ++nid;
        score = percent;
    }

    int Id() const
    {
        return id;
    }

    float GetScore() const
    {
        return score;
    }

    void SetScore(float value)
    {
        score = value;
    }

    virtual ~Student(){}

private:
    int id;
    float score;
};

用于访问和修改私有类成员的结构:

struct _Student
    {
        void* vptr;
        int id;
        float score;
    };

    _Student* bs3 = reinterpret_cast<_Student*>(bs2);
    bs3->id = 5;

谢谢。如果我错了,请纠正我/我不能以适当的方式提出我的问题。

5 个答案:

答案 0 :(得分:3)

  

$ 5.2.10 / 2 - “表达   积分,枚举,指针或   指向成员的类型可以是   显式转换为自己的类型;   这样的转换会产生其操作数的值。

这意味着指针'bs2'和'bs3'指向同一位置

  

$ 9.2 / 16 - “两个标准布局结构   (第9条)类型是布局兼容的   如果他们有相同的数量   非静态数据成员和   相应的非静态数据成员   (按照申报顺序)有   布局兼容类型(3.9)。“

这意味着您的类和结构与布局兼容。

$ 9 / 6-

  

标准布局类是一个类   那个:

     

- 没有非静态数据成员   类型非标准布局类(或   这类类型的数组)或参考,

     

- 没有虚函数(10.3)和没有   虚基类(10.1),

     

- 具有相同的访问控制(第11条)   所有非静态数据成员,

     

- 没有非标准布局基类,

     

- 要么没有非静态数据成员   在最派生的类中,最多   一个带有非静态数据的基类   成员,或没有基类   非静态数据成员和

     

- 没有与...相同类型的基类   第一个非静态数据成员.108

由于您的类具有虚拟析构函数,因此您的类和结构不是标准布局类。

但是你添加了一个'void *'数据成员来处理'vptr'(从而可能根据你的特定编译器实现模仿布局兼容性)

在这种情况下,reinterpret_cast用于将类指针(bs2)解释为结构指针(bs3)。默认情况下,struct成员是公共的。由于重新解释的返回值指向了类成员所在的同一内存(请参阅上面的引用),因此可以修改结构成员(与原始类成员相同)。

这是作弊。这是非常沮丧的。这很可能会导致未定义的行为

答案 1 :(得分:3)

  

但在某些情况下,我们应该继续访问它们。

那么,祈祷,这些情况是什么?

除了设计错误,我看不到任何错误。访问私人会员是不可取的。如果您需要访问权限,请通过合法方式提供,即要么使成员更容易访问,要么使用friend修饰符以受控方式访问它们。

违反C ++类型检查系统等于游戏结束:你欺骗编译器,不要指望它与你合作。有了这种未定义的行为(即不仅仅是平台依赖,但出于好的理由而被禁止),你只是以非常的形式引发麻烦,难以追踪错误。

tl; dr :不要。如初。

警告:有一个例外:您有一个无法访问/修改源代码的库,并且您无法影响其界面设计。 另外你可以肯定(怎么样?)它永远不会改变。在这种情况下,唯一的解决方案可能是用这些技巧破解库。

答案 2 :(得分:2)

我认为你或许应该稍微改变你的问题的背景。 如果您意识到您需要访问您班级中的私有变量 你正面临一个需要解决的设计问题而不是 使用不安全的类型转换进行攻击。即使它只是 假设并且为了在这里询问reinterpret_cast。

对于reinterpret_cast的用例,我说在哈希函数中有意义:

unsigned short Hash( void *p ) {

unsigned int val = reinterpret_cast<unsigned int>( p );
return ( unsigned short )( val ^ (val >> 16));

unsigned int val = reinterpret_cast<unsigned int>( p ); return ( unsigned short )( val ^ (val >> 16));

一些有用信息的链接:

When should static_cast, dynamic_cast, const_cast and reinterpret_cast be used?

http://advancedcppwithexamples.blogspot.com/2010/02/reinterpretcast-in-c.html

http://www.linuxtopia.org/online_books/programming_books/thinking_in_c++/Chapter03_054.html

答案 3 :(得分:1)

  

但在某些情况下,我们应该继续访问它们。

如果您必须在任何情况中访问它们,请更改其访问规范。

或者更好的是,创建一个接受令牌的公共方法(或一些特殊权限 - 验证调用者),并返回请求的值。

答案 4 :(得分:1)

你所拥有的是一个可怕的黑客攻击封装。如果确实想要访问私有变量,那么您应该使用“friend”关键字。 reinterpret_cast工作的原因是因为你将类Student的字节解释为struct _Student - 它的变量默认声明为public。有各种各样糟糕的方式来访问私人数据,这是我能想到的另一个方法:

int* bs3 = reinterpret_cast<int*>(bs2);
++bs3;
*bs3 = 5;

不要这样做是我的建议。