【C++基础】系列博客为参考《C++ Primer中文版(第5版)》(C++11标准)一书,自己所做的读书笔记。
本文为原创文章,未经本人允许,禁止转载。转载请注明出处。
1.访问控制与封装
在C++语言中,我们使用访问说明符(access specifiers)加强类的封装性。
- 定义在
public
说明符之后的成员在整个程序内可被访问,public
成员定义类的接口。 - 定义在
private
说明符之后的成员可以被类的成员函数访问,但是不能被使用该类的代码访问,private
部分封装了(即隐藏了)类的实现细节。
再一次定义Sales_data类,其新形式如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Sales_data{
public : //添加了访问说明符
Sales_data() = default;
Sales_data(const std::string &s, unsigned n, double p) : bookNo(s), units_sold(n), revenue(p*n) { }
Sales_data(const std::string &s) : bookNo(s) { }
Sales_data(std::istream&);
std::string isbn() const { return bookNo; }
Sales_data &combine(const Sales_data&);
private : //添加了访问说明符
double avg_price() const { return units_sold ? revenue/units_sold : 0; }
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
一个类可以包含0个或多个访问说明符,而且对于某个访问说明符能出现多少次也没有严格限定。每个访问说明符指定了接下来的成员的访问级别,其有效范围直到出现下一个访问说明符或者到达类的结尾处为止。
1.1.使用class或struct关键字
我们可以使用class或struct定义类。‼️使用class和struct定义类唯一的区别就是默认的访问权限:如果我们使用struct关键字,则定义在第一个访问说明符之前的成员是public
的;相反,如果我们使用class关键字,则这些成员是private
的。
2.友元
既然Sales_data的数据成员是private
的,我们的read、print和add函数也就无法正常编译了,这是因为尽管这几个函数是类的接口的一部分,但它们不是类的成员。
类可以允许其他类或者函数访问它的非公有成员,方法是令其他类或者函数成为它的友元(friend)。如果类想把一个函数作为它的友元,只需要增加一条以friend关键字开始的函数声明语句即可:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Sales_data{
//为Sales_data的非成员函数所做的友元声明
friend Sales_data add(const Sales_data&, const Sales_data&);
friend std::istream &read(std::istream&, Sales_data&);
friend std::ostream &print(std:: ostream&, const Sales_data&);
public :
Sales_data() = default;
Sales_data(const std::string &s, unsigned n, double p) : bookNo(s), units_sold(n), revenue(p*n) { }
Sales_data(const std::string &s) : bookNo(s) { }
Sales_data(std::istream&);
std::string isbn() const { return bookNo; }
Sales_data &combine(const Sales_data&);
private :
double avg_price() const { return units_sold ? revenue/units_sold : 0; }
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
//Sales_data接口的非成员组成部分的声明
//解释见第2.1部分
Sales_data add(const Sales_data&, const Sales_data&);
std::istream &read(std::istream&, Sales_data&);
std::ostream &print(std:: ostream&, const Sales_data&);
友元声明只能出现在类定义的内部,但是在类内出现的具体位置不限。友元不是类的成员也不受它所在区域访问控制级别的约束。
一般来说,最好在类定义开始或结束前的位置集中声明友元。
封装有两个重要的优点:
- 确保用户代码不会无意间破坏封装对象的状态。
- 被封装的类的具体实现细节可以随时改变,而无须调整用户级别的代码。
2.1.友元的声明
友元的声明仅仅指定了访问的权限,而非一个通常意义上的函数声明。如果我们希望类的用户能够调用某个友元函数,那么我们就必须在友元声明之外再专门对函数进行一次声明(类的外部)。
许多编译器并未强制限制友元函数必须在使用之前在类的外部声明。