1. 程式人生 > 程式設計 >c++訪問私有private成員變數的常用方法

c++訪問私有private成員變數的常用方法

類的物件不能直接訪問類宣告的私有成員變數,否則破壞了資訊隱藏的目的。

在C++中,為了防止某些資料成員或成員函式從外部被直接訪問,可以將它們宣告為private,這樣編譯器會阻止任何來自外部非友元的直接訪問。

私有成員變數的常用訪問方法如下:

(1)通過公共函式為私有成員賦值

#include <iostream> 
using namespace std; 
 
class Test 
{ 
private: 
	int x,y; 
public: 
	void setX(int a) 
	{ 
		x=a; 
	} 
	void setY(int b) 
	{ 
		y=b; 
	} 
	void print(void) 
	{ 
		cout<<"x="<<x<<'\t'<<"y="<<y<<endl; 
	} 
} ; 
 
int main() 
{ 
	Test p1; 
	p1.setX(1); 
	p1.setY(9); 
	p1.print( ); 
	return 0; 
} 

(2)利用指標訪問私有資料成員

#include <iostream> 
using namespace std; 
class Test 
{ 
private: 
	int x,y; 
public: 
	void setX(int a) 
	{ 
		x=a; 
	} 
	void setY(int b) 
	{ 
		y=b; 
	} 
	void getXY(int *px,int *py) 
	{ 
		*px=x;  //提取x,y值 
		*py=y; 
	} 
}; 
int main() 
{ 
	Test p1; 
	p1.setX(1); 
	p1.setY(9); 
	int a,b; 
	p1.getXY(&a,&b); //將 a=x,b=y 
	cout<<a<<'\t'<<b<<endl; 
	return 0; 
} 

(3)利用函式訪問私有資料成員

#include <iostream> 
using namespace std; 
class Test 
{ 
private: 
	int x,y; 
public: 
	void setX(int a) 
	{ 
		x=a; 
	} 
	void setY(int b) 
	{ 
		y=b; 
	} 
	int getX(void) 
	{ 
		return x;  //返回x值 
	} 
	int getY(void) 
	{ 
		return y;  //返回y值 
	} 
}; 
int main() 
{ 
	Test p1; 
	p1.setX(1); 
	p1.setY(9); 
	int a,b; 
	a=p1.getX( ); 
	b=p1.getY(); 
	cout<<a<<'\t'<<b<<endl; 
	return 0; 
} 

(4)利用引用訪問私有資料成員

#include <iostream> 
using namespace std; 
class Test 
{ 
private: 
	int x,y; 
public: 
	void setX(int a) 
	{ 
		x=a; 
	} 
	void setY(int b) 
	{ 
		y=b; 
	} 
	void getXY(int &px,int &py) //引用 
	{ 
		px=x;  //提取x,y值 
		py=y; 
	} 
}; 
int main() 
{ 
	Test p1,p2; 
	p1.setX(1); 
	p1.setY(9); 
	int a,b; 
	p1.getXY(a,b); //將 a=x,b=y 
	cout<<a<<'\t'<<b<<endl; 
	return 0; 
}

下面是其它網友的補充

訪問C++類物件中私有成員變數的方法

原則上,C++類中私有變數不允許在類之外的其他任何地方訪問,一般來說功能完善的類都會提供get,set方法來操作類屬性值,但如果沒有get、set方法都沒有提供,比如使用的是第三方提供的.o(或者動態庫)來進行開發的,並且實際應用中我們確確實實需要改變其中某個物件的一個私有引數,有沒有什麼辦法呢?我們知道,一個程序有程式段和資料段,如果我們知道了物件的資料空間,那麼得到該物件的成員變數值也就很簡單了,而實際上,物件資料段的首地址其實就是物件地址,以例子說明:

class A
{
public:
  int i;
  bool setJ(int _j){j = _j;};
  int getJ() const {return j;};
private:
  int j;
};

int main()
{
  A a;
  printf("a's address is %u.n",&a); // 列印物件a的地址
  printf("a.i's address is %u.n",(&(a.i))); // 列印物件a的成員變數i的地址
}

執行上面程式,可以看到結果,兩個值時一樣的,也就是說明物件地址就是第一個成員變數的地址。
我們知道,C++編譯器將資料和程式段分開,所有的類變數會按照宣告順序依次存入資料段,所以,如果知道了第一個變數的地址,那麼後面的地址也就依次累加即可逐一求出了。有了變數地址,那麼也就可以對它的值進行修改了。還是以上面的例子來說明,一下程式編寫了如何更改類成員b的值:

int main()
{
  A a;
  a.setJ(2);
  printf("before modified:the member j of a is %d.n",a.getJ()); // 列印j的值。
  int *p = (int *)(int(&a) + sizeof(a.i));
  *p = 10;
  printf("after modified:the member j of a is %d.n",a.getJ()); // 列印j的值。
}

可以得出此時j成員變數的值由2變成10了。

總結:直接對地址空間操作,請小心為妙。。。

此外,另附一篇與此類似的文章,也很有啟發性。

分析程式設計師和黑客的區別

題目:
  設有如下C++類

class A
{
 int value;
public:
 A(int n = 0) : value(n) {}
 int GetValue()
 {
  return value;
 }
};

請使用某種方式來在類的外部改變私有成員A::value的值。

程式設計師的可能做法:

class A
{
 int value;
public:
 A(int n = 0) : value(n) {}
 int GetValue()
 {
  return value;
 }
 void SetValue(int n)
 {
  value = n;
 }
};
void f()
{
 A a;
 a.SetValue(5);
}

黑客的可能做法:

void f()
{
 A a;
 *((int *)&a) = 5;
}

結論:

程式設計師習慣於遵循既有的限制來增加既有的東西。
黑客習慣於利用既有的東西來打破既有的限制。