类(二):访问控制与封装 (学习笔记)

利用访问说明符加强类的封装性;
    定义在public说明符之后的成员在整个程序内可以被访问,public成员定义类的接口;
    定义在private说明符之后的成员可以被类的成员函数访问,private部分隐瞒了类的实现细节。

例:

class Sales_data {
public:
Sales_data() = defult;
Sales_data(const std::string &s) :bookNo(s) {}
Sales_data(const std::string &s,unsigned n,double p):
bookNo(s),units_sold(n),revenue(p*n) {}
Sales_data(std::istream &s);
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;
};

   **使用class或struct关键字**
使用struct关键字,则定义在第一个访问说明符之前的成员是public,若用class关键字,则这些成员是private。

1.友元

    类可以允许其他类或者函数访问它的非公有成员,方法是令其他类或者函数成为他的友元(friend)。如果类
想把一个函数作为它的友元,只需要增加一条以friend关键字开始的函数声明语句即可。

例:
     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() = defult;
        Sales_data(const std::string &s) :bookNo(s) {}
        Sales_data(const std::string &s,unsigned n,double p):
                   bookNo(s),units_sold(n),revenue(p*n) {}
        Sales_data(std::istream &s);
        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;
        };

    //Sales_data接口的非成员组成部分的声明
    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.类的其他特性

 定义两个相互关联的类:Screen和Window_mgr

 **定义一个类型成员**
    class Screen{
     public:
          typedef std::string::size_type pos;
     private:
          pos cursor = 0;
          pos height =0; width =0;  //三个size_type类型的成员,表示光标的位置及屏幕的高和宽
          std:: string contents;   //保存Screen内容
          };
 (1)typedef 也可以等价的使用类型别名,如下所示:
       class Screen{
       public:  
       //使用类型别名等价地声明一个类型名字
       using pos = std::string::size_type'
       }
  (2)用来定义类型的成员必须先定义后使用。

   **Screen类的成员函数**
     class Screen{
     public:
          typedef std::string::size_type pos;
                             //需要默认的构造函数,必须显式的把它声明出来
          Screen() =default; //因为Screen()有另外一个构造函数,所以本函数是必须的 
          //cursor 被其类内初始值初始化为0
          Screen(pos ht,pos wd,char c):height(ht),width(wd),
          contents(ht *wd,c) {}                  
          char get() const                     //读取光标处的字符
                 {return contents[cursor];}   //隐式内联
          inline char get(pos ht, pos wd) const; //显示内联
          Scereen &move(pos r, pos c);
     private:
          pos cursor = 0;
          pos height =0; width =0;  //三个size_type类型的成员,表示光标的位置及屏幕的高和宽
          std:: string contents;   //保存Screen内容
          };
 **令成员作为内联函数**

  定义在类内部的成员函数是自动inline的。(内联函数的优点:提高程序的执行效率)
  在类的内部把inline作为声明的一部分显式地声明成员函数,同样的,也能在类的外部用inline关键字修饰函数的定义:

  **重载成员函数**

  **可变数据成员**

  **类数据成员的初始值**
  在C++11新标准中,可在类的定义时赋一个默认初始化的值。

3.类之间的友元关系

    例如:为Window_mgr添加一个名为clear的成员,它负责把一个指定的Screen的内容设置为空白。为了
完成这一任务,clear需要访问Screen的私有成员,若想令这种访问合法,Screen需要把Window_mgr指定成它的友元。
 class Screen {
              //Window_mgr的成员可以访问Screen类的私有部分
              friend class Window_mgr;
              //Screen类的剩余部分
              };
     如果一个类指定了友元类,则友元类的成员函数可以访问此类包括非公有成员在类的所有成员。则,我们可以将
Window_mgr的clear成员写成如下形式:
    class Window_mgr {
         public:
             // 窗口中每个屏幕的编号
             using ScreenIndex = std::vector <Screen>::size_type;
             //按照编号将指定的Screen重置为空白
             void clear(ScreenIndex);
          private:
              std::vector <Screen> screens{Screen(24,80,'')};
           };
           void Window_mgr::clear(ScreenIndex i)
           {
              //s是一个Screen的引用,指向我们想要清空的那个屏幕
              Screen &s =screen[i];
              //将那个选定的Screen重置空白
              s.contents = string(s.height *s.width,'');
           }
       **令成员函数作为友元**

  class Screen {
       //Window_mgr::clear 必须在Screen类之前被声明
       friend void Window_mgr::clear(ScreenIndex);
  };

         **函数重载和友元**
    如果一个类想把一组重载函数声明为它的友元,它需要对这组函数中的每一个分别声明:  

    // 重载的storeOn函数
    extern std::ostream& storeOn(std::ostream&, Screen &);
    exterm BitMap& storeOn (BitMap &, Screen &);
    class Screen{
              //storeOn的ostream版本能访问Screen对象的私有部分
              friend std::ostream& storeOn (std::ostream& ,Screen &);
    };
    **友元声明和作用域**      
    在类的内部定义该友元函数,我们也必须在类的外部提供相应的声明从而使得函数可见。我们仅仅是用声明友
 元的类的成员调用该友元函数,它也必须是被声明过的:
    struct X{
    friend void f() {/*友元函数可以定义在类的内部*/}
    X() {f();}          //错误:f还没有被声明
    void g();
    void h();
};

    void x::g() {return f():}   //错误:f还没有被声明
    void f();                   //声明那个定义在X中的函数
    void X::h(); {return f();}  //正确:现在f的声明在作用域中了    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值