下面以私有(private)成员为例,来说明C++是如何实现访问控制的。
在C++中,私有成员的名称只能被这些成员所在的类的内部成员函数和友元访问。
之所以强调”名称“是因为,C++的访问控制实际上是通过限制对名称的使用来实现的。
成员的名称既可以表示函数,也可以是数据成员,类型,常量等,跟名称表示的对象无关。
只要这些成员是属于这个类的,那么对成员名称的使用,就要受到C++的访问控制规则的约束。
在此,通过以下例子来说明问题:
如果在类中定义了一个私有的非静态类型,但是有个一在类的外部实现的成员函数,把这个私有类型当做其返回值。
那么这样做对吗?假如对,能在类的外面访问这个私有类型的public数据成员吗?
-
#include <iostream>
-
-
using namespace std;
-
-
class Link
-
{
-
private:
-
struct Node
-
{
-
Node(int d)
-
{
-
data = d;
-
prev = nullptr;
-
next = nullptr;
-
}
-
int data;
-
Node *prev;
-
Node *next;
-
};
-
-
Node *first;
-
Node *last;
-
public:
-
Link()
-
{
-
first = nullptr;
-
last = nullptr;
-
}
-
-
~Link()
-
{
-
Node *n1 = first, *n2;
-
while (n1)
-
{
-
n2 = n1->next;
-
delete n1;
-
n1 = n2;
-
}
-
}
-
-
void Append(int d)
-
{
-
Node *n = new Node(d);
-
if (first)
-
{
-
n->prev = last;
-
last->next = n;
-
last = n;
-
}
-
else
-
{
-
first = n;
-
last = first;
-
}
-
}
-
-
Link::Node* First();
-
};
-
-
Link::Node* Link::First()
-
{
-
return first;
-
}
-
-
int main(int argc, char* argv[])
-
{
-
Link l1;
-
l1.Append(100);
-
// 正确!并没有在类的外部使用私有成员的名称。编译器是通过类型推理得知n1的类型的。
-
auto *n1 = l1.First();
-
// 错误!不能在类的外部使用私有成员的名称。
-
// Link::Node * n1 = l1.First();
-
cout << n1->data << endl;
-
return 0;
-
}
输出结果为:
100
由以上例子说明,即使是私有类型,也可以作为类的public成员函数的返回值。
再来分析原因:
1,因为First函数是Link类的成员函数。并没有违反private访问控制规则(私有成员,可以被相同类内部的成员函数和友元访问)。
First和Node同属Link类,并且Node属于First函数成员签名的一部分,所以定义(或声明)返回私有成员的成员函数是合法的。
2,如果将main函数中auto *n1 = l1.First();修改为Link::Node *n1 = l1.First();,则会出现编译错误。
原因就是上面提到的,C++是通过限制对名称的使用来实现访问控制的。使用auto并没有违反规则,因为确实没有在类的外部使用私有成员的名称。
C++编译器通过类型推理,得知n1的类型是Link::Node*,data属于Node的public成员,所以是可以访问的。
阅读(1979) | 评论(0) | 转发(0) |