在类的定义中,会将一些不愿意被其他类直接使用的变量定义为private变量。要对类内的变量进行读取或修改,需要调用该类中的public方法。那么在编译过程中,是否真的只能通过类提供的公开的方法来修改其私有的变量吗?其实不然。
要获取类中的private变量,方法有很多,在这里就只介绍其中两种方法。
方法1:通过强制类型转换,使用外部指针访问类中的私有变量。
假如我们知道类中的private变量是char(或者char[ ])型。那么,当我们用char型指针指向类的时候,它会将类内的char(char[ ])型变量首地址交给指针,即使该变量是private型变量。如下面代码:
#include <iostream>
using namespace std;
class testClass{
private:
char a[30];
public:
void show(){
cout<<"a: "<<this->a<<endl;
}
};
int main()
{
testClass temp;
char *p;
p = (char*)&temp;
temp.show();
cout<<"p: "<<p<<endl;
*p = 'A';
temp.show();
system("pause");
return 0;
}
在类中,有a[30]是私有的,在main中用char型指针指向a是不被允许的。但是,当把指针指向类,并使用强制类型转换让类转换为char型指针,这时候,指针是能成功指向类的,而且指向的地址是&a[0]。此时,便可以借助指针p来对a[30]进行操作了。上述代码运行结果如下:
可以看到,第二行输出p时,输出的是a[30]的内容,而在对p所指向的内容做修改后,输出a[30],a[30]也被修改了。
方法2:利用地址分配的连续性。(此方法有局限性:1.地址需要已知,最好连续;2.需要有public变量作为中介)
第2种方法仅仅是用来输出变量,因为它是利用了cout中的write函数。假如知道了类中有一个public的变量(或指针)b和private变量(或指针)a,并且知道他们的地址,便可以利用b+write()来输出a。
首先我们看一下write函数:
它的参数有两个,第一个参数是(指向起始地址的)指针,表示从指针处开始打印,第二个参数是size,表示打印的长度。在这里需要知道:write()函数只会根据这两个参数打印相应的内容,即使遇到边界,它也会继续打印,此时打印的便是相邻内存块中的内容。所以,我们可以利用write函数做如下事情:
#include <iostream>
using namespace std;
class testClass{
private:
const char * a;
public:
const char * b;
testClass(){
this->b = new char[7];
this->a = new char[7];
b="I am B";
a="I'm A";
}
~testClass(){
delete this->a;
delete this->b;
}
void getAddress(){
cout<<"address of a:"<<(int)this->a<<endl;
cout<<"address of b:"<<(int)this->b<<endl;
}
};
int main()
{
testClass temp;
temp.getAddress();
cout.write(temp.b,14);
system("pause");
return 0;
}
代码中,类内有private型的指针a和public型的指针b,构造函数为它们new一片内存并写入不同的内容。在main函数中,我们先显示一下a和b的地址,然后利用write打印出b的内容,并让其越界。结果如下:
由结果可以看出,系统给a、b分配的存储空间地址块刚好是相邻的,于是,在打印完public的变量b之后,write函数又越界打印了与b相邻的,private的a中的内容。