C++ Encapsulation(封装)

OOP的主要有三个主要的特点。 一个是封装(Encapsulation),一个是继承(inheritance), 一个是多态(Polymorphism)。

首先我们说说封装。

一个数据类型, 比如说int, 我们声明一个int 变量, 该变量可以取的值(value)为0, 1, -1等。 但是数据类型不仅有值, 也有与之匹配的operations,例如 +, -,*, /, %以及一些内置函数 等等。所以我们不能把一个数据类型仅仅作为值那么简单。 所以。 A data type is values together with a set of basic operations defined on this values。 这也是我们自定义的数据类型类(class)具有成员函数的原因了。

ADT(abstract data type, 抽象数据类型): 如果使用某类型的程序员无法知道该类型变量的值和operations 如何去implemented, 我们就说这个数据类型为抽象数据类型(ADT)。 内置的数据类型, 例如int,, 就是一个ADT, 因为你并不知道operations such as + and * 等是如何实现的(implemented)。 即使你知道了实现细节, 你也不知道如何去运用这些信息。 你只是知道运用相应的operations, 得到你期望的结果, 仅此而已。

class, 是用户自定义的数据类型, 也应该是一个ADT, 也就是抽象数据类。 也就是说class的operations 的实现细节对于使用该类的程序员是hidden的。 也就是说, 这些成员函数是public的, 一个使用该类的程序员不需要知道成员函数的定义, 就可以使用这个成员函数。 该程序员仅需要知道类定义中成员函数的声明, 加上一行注释即可。

另外, 除了成员函数, 对于类的数据(成员变量), 使用这个类的程序员也不需要知道数据是如何implemented。 这也可以是隐藏的。 例如在上例子中, 类DayOfYearde 日期数据, 程序员不知道月份March 究竟是被实现成了int的数据类型3, 还是字符串‘March’, 这也是程序员不需要关心的。 

上述的特点通常被称为information hiding(信息隐藏), 或者data abstraction, 或者封装(encapsulation)(当谈到OOP的概念的时候, 最常说的是encapsulation,即封装)。一句话, 封装的含义就是类的实现细节对于使用该类的程序员是隐藏着的(hidding)。

实现封装的一个准则(principle)就是将所有的成员变量声明为private的。

 

Public and private members

在类定义中, 所有在关键子, access modifier ‘private’的之后的所有Item 都是private的,这样的成员只能通过类的成员函数存取。 ‘public’ 之后的所有item均为public, 公开变量或者公开函数可以直接通过对象和相应的点运算直接存取, 当然类的成员函数也可以看到这些公开成员的存在。

class DayOfYear {
   public:
      void inout();
      void output();
      
      //two accessor
      void set(int newMonth, int newDay);
      //Postcondition: newMonth and newDay form a possible date
      
      void set(int newMonth);
      //precondition: 1 <=  newMonth <=12
      //Postcondition: The date is set to the first day of the given month
      
      //two mutator
      int getMonthNumber();// returns 1 for January , 2 for february, etc
      int getDay(); 
      
   private:
      int month;
      int day;
}; // 这个分号必不可少, 是类定义的一部分


如上, 声明的类:

DayOfYear toay; //okay

today.month =12; //illegal

today.day = 25; //illegal

cout << today.monrh;//illegal

if(today.month == 1)  //illegal

   cout << "January";

一旦我们声明一个成员变量为private的, 那么我们只能通过调用成员函数来修改或者读取这个成员函数, 除此之外, 没有任何办法。

也就是说, 类的数据(data)被隐藏了。

对于public的类成员, 我们可以在任何地方直接使用。通常, 一个很好的编程惯例就是将所有的成员函数声明为共有的(public), 所有的成员变量声明为

私有的(private)。 虽然我们可以有多个public sections 和private sections, 但是最好的情况下, 我们只选择一个public section, 一个private sections.

且这两个区域出现的次序是没有限制的。

如果我们选则private section在前, 那么private: 是可以省略的, 因为默的情况是私有变量(这点和struct 不同, struct的默认存取方式是public的)

但是如果我们选择public sections 在前, 就都不能省略了。 许多的程序员选择先public sections, 然后private sections.

Accessors 和mutators 函数

首先, 值得声明的是, 这两种函数属于类的成员函数。

Accessors functions 的作用是读取数据

mutators 的作用是修改或者更新数据

 

下面结合上面的内容, 举一个例子, 便于理解。

 

#include <iostream>
#include <cstdlib>
using namespace std;

class DayOfYear {
   public:
      void input();
      void output();

      //two accessor
      void set(int newMonth, int newDay);
      //Postcondition: newMonth and newDay form a possible date

      void set(int newMonth);
      //precondition: 1 <=  newMonth <=12
      //Postcondition: The date is set to the first day of the given month

      //two mutator
      int getMonthNumber();// returns 1 for January , 2 for february, etc
      int getDay();

   private:
   //private members
      int month;
      int day;
}; // 这个分号必不可少, 是类定义的一部分

int main() {
   DayOfYear today, bachBirthday;//使用类声明了两个对象
   cout << "Enter today's date: \n";
   today.input();
   cout << "Today's Date is: ";
   today.output();
   cout << endl;

   bachBirthday.set(3, 21);
   cout << "bach's birthday is: ";
   bachBirthday.output();
   cout << endl;
   if (today.getMonthNumber() == bachBirthday.getMonthNumber() && today.getDay() == bachBirthday.getDay())
      cout << "Happy Birthday! \n";
   else
      cout << "Happy Unbirthday! \n";
   return 0;
}
//two mutator functions , 重载了set函数
void DayOfYear::set(int newMonth, int newDay) {
   if((newMonth >= 1) && (newMonth <= 12))
      month = newMonth;
   else {
      cout << "Illegal month value! Program aborted.\n";
      exit(1);
   }

   if((newDay >= 1) && (newDay <= 31))
      day = newDay;
   else {
      cout << "Illegal day value! Program aborted.\n";
      exit(1);
   }
}

void DayOfYear::set(int newMonth) {
   if((newMonth >= 1) && (newMonth <= 12))
      month = newMonth;
   else {
      cout << "Illegal month value! Program aborted.\n";
      exit(1);
   }

   day = 1;
}

//two accessor functions
int DayOfYear::getMonthNumber() {
   return month;
}

int DayOfYear::getDay() {
   return day;
}
//**********
void DayOfYear::input() {
   cout << "Enter the month as a number: ";
   cin >> month;
   cout << "Enter the day of the month: ";
   cin >> day; //private members can only be used in member functions definitions, but not elsewhere

   if ((month < 1) || (month > 12) || (day < 1) && (day > 31)) {
      cout << "Illegal date! Program aborted.\n";
      exit(1);
   }
}


void DayOfYear::output() {
   switch (month) { //根据month, month是成员变量,成员函数可以直接存取(access)
      case 1:
         cout << "January "; break;
      case 2:
         cout << "February "; break;
      case 3:
         cout << "March "; break;
      case 4:
         cout << "April "; break;
      case 5:
         cout << "May "; break;
      case 6:
         cout <<  "June "; break;
      case 7:
         cout << "July "; break;
      case 8:
         cout << "August "; break;
      case 9:
         cout << "September "; break;
      case 10:
         cout << "October "; break;
      case 11:
         cout << "November "; break;
      case 12:
         cout << "December "; break;
      default:
         cout << "Error!";
   }

   cout << day; // 成员变量, 可以直接存取
}


运行结果为:

 

 

Structures 和class的区别:

structures: normally with all member variables and no member functions。 尽管结构体也可以由成员函数, 但是为了便于区分, C++中一般不这样用struct。

一个最重要的区别就是, 如果没有写access modifier, 类中默认为private, 而struct中默认这样的成员为public的。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值