正常来说,类外无法访问类内的private成员,只能通过类内成员访问private成员,在类外,无论是通过类指针还是类对象都无法直接访问类中的private成员
C++类中的私友成员是不能通指针操作的。
#include <iostream>
using namespace std;
class A
{
int a;//private
public :
int b;//public
void f1 () {cout<<a;}
A (){a=3;b=4;c=&a;}
int* c;
private:
int a;
};
int main()
{
int A::*p=&A::b;//vaild
p=A::c;//vaild;
p=A::a;//invaild
return 0;
}
但是正常情况下,一般构造函数设置为public,成员变量设置为private,一般在类的外部,编译器调用构造函数,是可以调用的,而构造函数作为一个类内成员,可以直接访问类中的私有成员变量。并对私有成员变量进行赋值,这也就是一般创建一个对象,并给对象初始化的过程。但是如果如上图是一个指针的形式,那么这个指针作为类外的成员,不可以访问私有成员a。
但是可以通过下面的方式间接地修改私有成员变量
#include <iostream>
using namespace std;
class A
{
public:
A(int i = 0)
:m_i(i)
{}
void print()
{
cout << "m_i" << this->m_i << endl;
}
private:
int m_i;
};
int main(int argc, char **argv)
{
A a(10);
// 初始化后的a的私有变量是10
a.print();
//可以通过指针访问a中的m_i变量
int *pi = (int *)&a;
cout << "a::m_i: " << *pi << endl;
//通过指针更改m_i
*pi = 11;
//我们看到对象a中的私有变量m_i已经被改变
a.print();
return 0;
}
运行结果:
m_i: 10
a::m_i: 10
m_i: 11
在上面代码中,a对象有一个私有的数据成员m_i,原则上在类外部是不能对m_i进行访问的。但是我们可以通过地址访问对象的私有数据成员m_i。并且还对其进行了修改。运行结果也表明我们确实可以通过指针访问对象的私有成员并且可以对其进行修改。因为对象本身作为一个地址值,里面存放的只有虚函数指针和成语变量,如果没有虚函数指针那么就可以直接访问到第一个成员变量,且一个对象的大小就是这些,没有成员函数,没有static的成员变量。类的大小是虚函数表和一般的成员变量,也没有成员函数。成员函数放在代码区。
究其原因,在C++中访问对象的数据成员,可以根据数据在对象中的偏移地址访问。C++的对象其实就是一个指针数组。这个指针数组存放的是对象的虚函数表和数据成员的地址,我们当然可以通过指针访问对象的任何成员。我想着可能是C++为了兼容C语言而留下的一些不是很安全的做法。
也可以采用类内写一个public接口,类外通过访问这个接口操作私有变量,因类内成员可以访问private成员
这种方式类似于构造函数设置成public,供编译器调用。
class Test
{
public:
void SetA(int _a)//接口(可以从类外设置a的值)
{
a = _a;
}
void Print()
{
cout << a << endl;
cout << b << endl;
cout << endl;
}
private:
int a = 10;
int b = 100;
};
int main()
{
Test s;
s.Print();
s.SetA(0);//通过接口把a设置为0;
s.Print();
Test* ps = &s;
int * ps1 = ((int *)ps + 1);
*ps1 = 0;//通过指针把b设置为0;
s.Print();
system("pause");
return 0;
}
结果如下: