7-2 访问控制与封装
7.2.0 目标代码
#include<iostream>
using namespace std;
class Sale_data{
//为Sale_data的非成员函数所做的友元声明
friend istream &read (istream &, Sale_data &);
friend ostream &print(ostream &, Sale_data &);
public : //后面跟接口
Sale_data() = default;
Sale_data (string s) : bookNo(s) {}
Sale_data(string s, unsigned n, double p) :
bookNo(s), units_sold(n), revenue(n*p) {}
Sale_data(istream &);
string ibsn() const {return bookNo;}
Sale_data& combine(Sale_data& );
private :
double avg_price() const;
//数据成员
string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
7.2.1 访问说明符
在c++语言中,我们使用访问说明符(access specifiers)加强类的封装性
- 定义在public说明符之后的成员:在整个程序内可被访问, public成员定义类的接口。
- 定义在private说明符之后的成员:可以被类的成员函数访问,但是不能被使用该类的代码访问,private部分封装了(即隐藏了)类的实现细节。
- 一个类可以包含0或多个访问说明符,对于某一个访问说明符的数量也没有限制
- 每个访问说明符的作用到下一个访问说明符之前或结尾
7.2.2 class 和 struct
使用class和struct定义类唯一的区别就是默认的访问权限。
- class : 默认 private
- struct : 默认 public
7.2.3 类的构成与友元
类的构成图
类的结构图
友元
在类的外部,非成员的接口函数无法访问 private 的函数成员,而它又是接口函数,需要像其他接口函数一样能够访问类的非公有成员,那么如何解决此冲突呢? 在类中声明友元
类可以允许其他类或者函数访问它的非公有成员,方法是令其他类或者函数成为它的友元
声明友元: friend
关键字
class Sale_data{
//为Sale_data的非成员函数所做的友元声明
friend istream &read (istream &, Sale_data &);
friend ostream &print(ostream &, Sale_data &);
//其他与之前一致
/*
. . .
. . .
*/
友元类以及友元成员函数
windows,screen是两个类,windows类有一个成员函clear,作用是情况指定screen类的内容。要达成注意功能
-
将windows声明为screen的友元类,windows可以访问screen中的所有成员,包括非公有成员
class screen{ friend class windows; /* . . . */ }
-
将clear函数声明为screen的友元函数
class screen{ //clear已经声明 friend void windows::clear(screen &); }
-
声明友元函数时需要注意声明顺序
- 先定义windows类,声明clear函数,但不能定义它。
- 定义screen类,声明clear为它的友元
- 定义clear函数
关于友元声明的几个注意点
友元声明只表示访问权限,不能代替函数声明。如在类Sale_data类内部中对print进行了友元声明,但是如果要使用print函数的话仍需要独立声明print函数
struct x { friend void f() {/*友元函数可以直接定义在内部*/}; x() {f();} //错误,f()没有被声明 void h(); void g(); }; void x::h(); //错误:f()没有被声明 void f(); void x::g() {return f();} //正确
友元不具有传递性,某一个类的友元之间不互为友元
完整代码2
#include<iostream>
using namespace std;
class Sale_data{
friend istream &read (istream &, Sale_data &);
friend ostream &print(ostream &, Sale_data &);
public :
//构造函数
Sale_data() = default;
Sale_data (string s) : bookNo(s) {}
Sale_data(string s, unsigned n, double p) :
bookNo(s), units_sold(n), revenue(n*p) {}
Sale_data(istream &);
//关于Sale_data对象的操作函数
string ibsn() const {return bookNo;}
Sale_data& combine(Sale_data& );
private :
double avg_price() const;
//数据成员
string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
//非成员函数接口
istream &read (istream &, Sale_data &);
ostream &print(ostream &, Sale_data &);
//外部构造函数
Sale_data::Sale_data(istream &is){
read(is, *this);
}
istream &read(istream &is, Sale_data &item){
double price = 0;
is >> item.bookNo >>item.units_sold >> price;
item.revenue = price * item.units_sold;
return is;
}
ostream &print(ostream &os, Sale_data &item){
os << item.bookNo << " " << item.units_sold << " "
<< item.revenue<<endl;
return os;
}
//外部成员函数
Sale_data& Sale_data::combine(constSale_data& trans){
units_sold += trans.units_sold;
revenue += trans.revenue;
return *this;
}
double Sale_data::avg_price() const{
if(units_sold != 0)
return revenue/units_sold;
else
return 0;
}
int main(){
Sale_data item(cin);
print(cout, item);
return 0;
}