c++primer第七章(类)【7.2】

7.2访问控制与封装

在上一章,我们已经定义了一个抽象数据结构,并且为类定义了接口,但是我们并没有任何机制来强制用户使用这些接口,我们的类并没有封装,也就是说,用户可以直接访问sales_data对象内部并且控制它的具体实现。在c++中,我们应该使用访问说明符(access specifiers)加强类的封装性:

  • 定义在public说明符之后的成员在整个程序都可以访问,public成员定义类的接口。
  • 定义在private说明符之后的成员可以被类的成员函数访问,但是不能被使用该类的代码分文,private部分封装了(隐藏了)类的实现细节。

再一次定义sales_data类:

class sales_data {
public:
//构造函数和部分成员函数在public之后,作为接口的一部分
	sales_data() = default;
	sales_data(const string&s):bookNo(s){}
	sales_data(const string &s , unsigned n ,double p):bookNo(s),unit_sold(n),revenue(p*n){}
	sales_data(istream& is);
	string isbn() const { return bookNo; }
	sales_data& combine(const sales_data&);
//数据成员和作为实现部分的函数在private说明符后面
private:
	double avg_price() const;
	string bookNo = "qqq";
	unsigned unit_sold{0};
	double revenue = 0;
};

NOTE:

1、构造函数和部分成员函数在public之后,作为接口的一部分

2、数据成员和作为实现部分的函数在private说明符后面

使用class或者struct关键字

我们可以使用class和struct关键字来定义类,唯一的区别是struct和class的默认访问权限不太一样。

struct在第一个访问说明符之前是public;class则是private。

7.2.1友元

既然我们重新定义了sales_data的数据成员属性为private,我们read,print,add函数也就无法正常编译了,因为这几个尽管是函数接口的一部分,但是它们不是类成员。

类可以允许其他类或者函数访问它的非公有成员,方法就是令其他类或者函数称为它的友元。

语法:添加一条以friend关键字开始的函数声明语句即可。

TIP:友元声明只能出现在类定义的内部,一般来说最好的类定义开始或结束前的位置集中声明友元。

class sales_data {
//为sales_data的非成员函数所做的友元声明。
friend sales_data add(const sales_data&,const sales_data &);
friend istream& read(istream&,sales_data &);
fiend ostrean& print(ostream&,const sales_data &);
public:
	sales_data() = default;
	sales_data(const string&s):bookNo(s){}
	sales_data(const string &s , unsigned n ,double p):bookNo(s),unit_sold(n),revenue(p*n){}
	sales_data(istream& is);
	string isbn() const { return bookNo; }
	sales_data& combine(const sales_data&);
private:
	double avg_price() const;
	string bookNo = "qqq";
	unsigned unit_sold{0};
	double revenue = 0;
};
//sales_data解耦的非成员组成部分的声明。
sales_data add(const sales_data&,const sales_data &);
istream& read(istream&,sales_data &);
ostrean& print(ostream&,const sales_data &);

关键概念:封装的益处

封装有两个重要的优点:

  • 确保用户代码不会无意间破坏封装对象的状态
  • 被封装的类具体实现细节随时可以改变,而无需调整用户级别的代码。

把数据成员设置为private,两个好处:

  • 类的作者就可以比较自由的修改数据了。只要类的接口不变,用户代码就无需改变。(不懂!!)如果数据是public,则所有使用了原来数据成员的代码都可能失效。这时我们必须定位并重写所有依赖于老版本实现的代码,之后才能重新使用该程序???
  • 放置用户的原因造成数据被破坏。如果我们发现程序缺陷破坏了对象的状态,则可以在有限的范围内定位缺陷:因为只有实现部分的代码可能产生这样的错误。因此,将查错限制在有限范围内可以极大降低维护代码及修正程序错误的难度。

NOTE:类的定义改变时无需更改用户代码,但是使用该类的源文件必须重新编译。

友元的声明

        友元的声明仅仅指明了访问的权限,但并不是函数声明。如果我们希望类的用户能调用某个友元函数,则必须在友元声明之外,专门进行一次函数声明。

        为了使友元对类的用户可见,我们通常把友元的声明与类本身放置在同一个头文件中(类的外部)(?????类的外部,不是在类定义开始或者是结束前集中声明吗???)。因此我们sales_data头文件应该为read,print,add提供独立的声明。(除类内部的友元声明之外)。

猜你喜欢

转载自blog.csdn.net/qq_34269988/article/details/86261742