3

我只是在浏览一些 C++ 代码。我在哪里遇到了reinterpret_cast运营商的概念。

编辑 1:

我知道不建议访问类的私有成员。 但在某些情况下,我们应该继续访问它们。 我刚刚提出这个问题是为了弄清楚我的概念。

在我提到的示例中,通过简单地创建具有相同变量的结构来访问 Class 的私有成员,然后通过实现 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;

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

4

5 回答 5

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)。默认情况下,结构成员是公共的。由于 reinterpret cast 的返回值指向类成员所在的同一个内存(参考上面的引用),所以可以修改结构成员(与原始类成员相同)。

这是作弊。这是非常不鼓励的。!这很可能会导致未定义的行为

于 2010-09-29T09:40:49.410 回答
3

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

祈祷,这些情况是什么?

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

违反 C++ 类型检查系统就等于游戏结束:你欺骗了编译器,不要指望它会和你一起工作。对于这种未定义的行为(即不仅依赖于平台,而且出于充分的理由而被禁止),您只是在以非常难以跟踪的错误的形式招致麻烦。

tl;博士:不要。曾经。

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

于 2010-09-29T10:00:55.727 回答
2

我认为您也许应该稍微改变一下您的问题的上下文。如果您意识到需要访问类中的私有变量,那么您将面临一个需要解决的设计问题,而不是使用不安全的类型转换来解决问题。即使这只是假设并且为了在这里询问 reinterpret_cast 。

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

unsigned short Hash( void *p ) {

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

}

一些有用信息的链接:

什么时候应该使用 static_cast、dynamic_cast、const_cast 和 reinterpret_cast?

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

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

于 2010-09-29T10:37:49.070 回答
1

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

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

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

于 2010-09-29T09:49:49.173 回答
1

你所拥有的是围绕封装的可怕黑客攻击。如果你真的想访问私有变量,那么你应该使用“friend”关键字。reinterpret_cast 起作用的原因是因为您将 Student 类的字节解释为 struct _Student - 它的变量默认声明为 public。访问私有数据的方式有很多种,这是我能想到的另一种方式:

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

只是不要这样做将是我的建议。

于 2010-09-29T10:14:49.953 回答