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 类的构成与友元

类的构成图

类的结构图

7-2 访问控制与封装

友元

在类的外部,非成员的接口函数无法访问 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;
}
上一篇:WinDbg调试分析 asp.net站点 CPU100%问题


下一篇:centerpoint模型说明