我正在尝试通过偏移来访问和修改类的私有数据成员 AFAIK,首先是计算偏移量,然后通过偏移量访问成员 这是我的代码。
class Test {
public:
int a;
int b;
private:
int c;
};
Test test;
cout << *(&test + &Test::b + 1); // access c
我收到错误:“+”运算符无效,右操作数包含“int Test::*
”类型。
There是一个类似的帖子,printf
ab
的偏移量为1,4
,但尝试这样时:
cout << &Test::a << '\t' << &Test::b;
我得到1 1
。
我的问题:
1.为什么cout
得到错误的结果?
2. Test::*p
指向什么?
3.如何访问和修改Test :: *指针?(或者当不知道偏移时如何访问私有成员?)
答案 0 :(得分:3)
Test::p
是成员指针。成员指针与常规指针不同。你不能只对它们做指针算术。它们不是对内存中某个位置的引用;它们是一种特殊的物体。
如果你想要一个指向对象的常规指针(即:现有类的成员),你必须得到指向那段特定内存的指针。
&test.b
BTW,无论您尝试访问的私人数据是出于某种原因而私有 。因此,除非你有一个非常非常的理由基本上打破内存保护(以及可移植性,因为这是完全未定义的行为),你不应该这样做。
答案 1 :(得分:3)
这有效:
#include <iostream>
using namespace std;
class test {
public:
int a;
int b;
test () : c(100) {}
void show () {cout << "c = " << c << endl;}
private:
int c;
};
int main (void)
{
test x;
test *ptr;
ptr = &x;
ptr++;
ptr = (test *) ((int *)ptr - 1);
cout << "c = " << *((int *)ptr) << endl;
*((int *)ptr) = 200;
x.show ();
return 0;
}
但应该知道偏移量。在上面的ptr
类型为test
,因此ptr++
会将指针值增加到sizeof (test)
。因为私有成员c
的位置在末尾并且是一个整数类型,所以通过先将ptr
强制转换为int *
然后递减1来减少一个整数步骤,现在指向到c
的地址。它首先打印,然后通过首先将c
投射到ptr
然后分配值然后打印来修改int *
的值。
当您知道c
的位置时,无法保证始终获得c
的值,因为填充在其他情况下可能会有所不同。此外,没有必要访问私有数据成员,因为在对象设计方法时,它被成员函数访问,并且是通过提供抽象来组织的工具。当在其他语言(如没有面向对象的功能)的其他语言中实现这样的概念时,您可以通过亲自遵循约定来实现这样的私有 - 公共环境,但是如果您访问了“私有”,编译器将不执行任何操作。实际上不应该。但是在C ++中,编译器提供了限制并阻止您转移和破坏您所创建的面向对象的设计。在运行时所有内存中,您可以访问它们,而不受您的代码的任何限制,无论是私人还是公共。如果您知道如何解释可执行文件中的字节,您可以更改任何您喜欢的内容,甚至是代码本身。我不认为这是一个好主意,因为它会使代码变得不可预测和不可移植,并且肯定违反了OOD方法。
答案 2 :(得分:2)
如果必须,#define private public
技巧应该这样做。
答案 3 :(得分:1)
你真的无法测试对象的内存布局。编译器可以随意使用它。
当成员被不同的访问说明符分隔时,该语言没有说明他们的顺序。在您的情况下,a
必须后跟b
,但理论上c
可以放在编译器认为合适的任何位置。
在一个更大的例子中,如
class Test {
public:
int a;
int b;
private:
int c;
protected:
double d;
};
例如,如果可以改善对齐,则允许编译器在d
之前放置c
。