We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
在课上,我们学习了类中的三种访问说明符public,protected,private。这三种访问说明符被用于访问控制。
public
protected
private
能被本类的成员函数、友元函数、本类的对象、其派生类的成员函数等访问。
能被本类的成员函数、友元函数、其派生类的成员函数访问;
能被本类的成员函数、友元函数访问。
可以看到,类的访问控制体现了面向对象编程的封装性。
这些访问说明符不会影响类的结构和对象的创建,在编译期间,所有的访问说明信息会消失。因此,可以看成,访问说明符是让编译器检查程序员是否进行了不应该的访问操作,而非严格禁止了这些访问操作。但编译器必须明确知道程序员在进行权限外的访问操作,才会产生访问权限错误。 因此,我们可以解释课上的题目:
#include <iostream> using namespace std; class A { private: int a; void f(int i=2) { a = i; } public: void f(int i, int j=2) { a = i + j; } int get_a() { return a; } }; int main() { A aa; aa.f(1);//A中函数重载冲突 cout << aa.get_a() << endl; return 0; }
进一步了解,编译器是通过限制“名称”的使用来进行访问控制的,无论是对成员变量、成员函数,甚至成员结构、成员类等,都是如此。 #include <iostream> using namespace std; class A { private: struct B { int c; B(int d) { c = d; } }; public: B* b; A() {} ~A() {} }; int main() { A a1; // 正确!并没有在类的外部使用私有成员结构的名称。编译器是通过类型推理得知n1的类型的。 auto *n1 = a1.b; // 错误!不能在类的外部使用私有成员的名称。 // Link::Node * n1 = a1.b; return 0; } 所以,这样的操作也能实现。
进一步了解,编译器是通过限制“名称”的使用来进行访问控制的,无论是对成员变量、成员函数,甚至成员结构、成员类等,都是如此。
#include <iostream> using namespace std; class A { private: struct B { int c; B(int d) { c = d; } }; public: B* b; A() {} ~A() {} }; int main() { A a1; // 正确!并没有在类的外部使用私有成员结构的名称。编译器是通过类型推理得知n1的类型的。 auto *n1 = a1.b; // 错误!不能在类的外部使用私有成员的名称。 // Link::Node * n1 = a1.b; return 0; }
所以,这样的操作也能实现。
调用aa.f(1)时,先会发生函数重载冲突问题,该程序无法通过编译。 之后,我们很容易会想到,通过指针等方法可以强制访问private成员。
aa.f(1)
#include <iostream> using namespace std; class { public: A() { a2 = 3; a3 = 4; } int* fun3() { cout << "a3=" << a3 << endl; return &a3; } int* fun2() { cout << "a2=" << a2 << endl; return &a2; } protected: int a2; private: int a3; }; int main() { A itema; int* mytest; //不能直接获取 //cout << "直接获取private值a3=" << itema.a3 << endl; mytest = itema.fun3(); cout << "通过指针获取private值a3=" << *mytest << endl; *mytest = 1; cout << "对private值进行修改:"; itema.fun3(); mytest = itema.fun2(); cout << "通过指针获取protected值a2=" << *mytest << endl; *mytest = 1; cout << "对protected值进行修改:"; itema.fun2(); return 0; }
输出为:
a3=4 通过指针获取private值a3=4 对private值进行修改:a3=1 a2=3 通过指针获取protected值a2=3 对protected值进行修改:a2=1
不过这么做显然不合类的创建者本意,对大多数程序也是有害的。
class A { int value; public: A(int n = 0) : value(n) {} int GetValue() { return value; } void SetValue(int n) { value = n; } };
当然,本例中也可以
A a; *((int *)&a) = 100;
用这种方式修改a中value的值为100。
a
value
在类中,被访问说明符限定的变量通常会在内存中顺序存放,而不同的访问说明符限定的变量存放位置可能不同。因此,通过获得对象地址,并直接计算出 private或protected成员的地址,来进行访问的操作并不总有效。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
C++中类的访问控制
访问说明符
在课上,我们学习了类中的三种访问说明符
public
,protected
,private
。这三种访问说明符被用于访问控制。public
能被本类的成员函数、友元函数、本类的对象、其派生类的成员函数等访问。
protected
能被本类的成员函数、友元函数、其派生类的成员函数访问;
private
能被本类的成员函数、友元函数访问。
可以看到,类的访问控制体现了面向对象编程的封装性。
C++中访问控制的实现
这些访问说明符不会影响类的结构和对象的创建,在编译期间,所有的访问说明信息会消失。因此,可以看成,访问说明符是让编译器检查程序员是否进行了不应该的访问操作,而非严格禁止了这些访问操作。但编译器必须明确知道程序员在进行权限外的访问操作,才会产生访问权限错误。
因此,我们可以解释课上的题目:
调用
aa.f(1)
时,先会发生函数重载冲突问题,该程序无法通过编译。之后,我们很容易会想到,通过指针等方法可以强制访问
private
成员。输出为:
不过这么做显然不合类的创建者本意,对大多数程序也是有害的。
访问
private
和protected
成员getter和setter方法
当然,本例中也可以
用这种方式修改
a
中value
的值为100。The text was updated successfully, but these errors were encountered: