我刚刚浏览了一些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;
谢谢。如果我错了,请纠正我/我不能以适当的方式提出我的问题。
答案 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;
不要这样做是我的建议。