Skip to content
New issue

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

类的访问控制相关 #43

Open
BBQGOD opened this issue Apr 1, 2021 · 0 comments
Open

类的访问控制相关 #43

BBQGOD opened this issue Apr 1, 2021 · 0 comments

Comments

@BBQGOD
Copy link

BBQGOD commented Apr 1, 2021

C++中类的访问控制

访问说明符

在课上,我们学习了类中的三种访问说明符publicprotectedprivate。这三种访问说明符被用于访问控制。

public

能被本类的成员函数、友元函数、本类的对象、其派生类的成员函数等访问。

protected

能被本类的成员函数、友元函数、其派生类的成员函数访问;

private

能被本类的成员函数、友元函数访问。

可以看到,类的访问控制体现了面向对象编程的封装性。

C++中访问控制的实现

这些访问说明符不会影响类的结构和对象的创建,在编译期间,所有的访问说明信息会消失。因此,可以看成,访问说明符是让编译器检查程序员是否进行了不应该的访问操作,而非严格禁止了这些访问操作。但编译器必须明确知道程序员在进行权限外的访问操作,才会产生访问权限错误。
因此,我们可以解释课上的题目:

#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;
}

所以,这样的操作也能实现。

调用aa.f(1)时,先会发生函数重载冲突问题,该程序无法通过编译。
之后,我们很容易会想到,通过指针等方法可以强制访问private成员。

#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

不过这么做显然不合类的创建者本意,对大多数程序也是有害的。

访问privateprotected成员

getter和setter方法

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;

用这种方式修改avalue的值为100。

在类中,被访问说明符限定的变量通常会在内存中顺序存放,而不同的访问说明符限定的变量存放位置可能不同。因此,通过获得对象地址,并直接计算出 privateprotected成员的地址,来进行访问的操作并不总有效。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant