一、类的封装
- 封装的含义: 
  - 所有属性都是私有的,外部不能直接访问
- 提供与属性相关的成员函数,间接访问属性
 
模板代码:
#include <iostream>
using namespace std;
class Clock {
private:
    int hour, minute, second;
public:
    Clock();							  // 声明无参构造函数,用缺省值初始化对象
    Clock(int newH, int newM, int newS);	// 声明有参构造函数,用传入的参数初始化对象
    
    // 内联函数,设置属性的值
    void setHour(int hour) {
        this->hour = hour;	// 将外部传入的值赋给属性
    }
    void setMinute(int minute) {
        this->minute = minute;
    }
    void setSecond(int second) {
        this->second = second;
    }
    // 获得属性的值
    int getHour() {
        return hour;
    }
    int getMinute() {
        return minute;
    }
    int getSecond() {
        return second;
    }
    
    void display() {
        cout << hour << ":" << minute << ":" << second << endl;
    }
};
// 定义无参构造函数,给hour、minute、second赋初值为1
Clock::Clock(): hour(1), minute(1), second(1) {  
}
/* 推荐写法:
Clock::Clock() {
    this->hour = 1;
    this->minute = 1;
    this->second = 1;
}
*/ 
// 定义有参构造函数,给hour、minute、second赋初值为传入的参数值
Clock::Clock(int newH, int newM, int newS): hour(newH), minute(newM), second(newS) { 
}
/* 推荐写法:
Clock::Clock(int newH, int newM, int newS) {
    this->hour = newH;		// 将传入的hour值赋给hour属性
    this->minute = newM;
    this->second = newS;
}
*/ 
int main() {
    
    Clock myClock1;		// 定义对象,此时自动调用无参构造函数
    cout << "利用无参构造函数创建的时间对象为:";
    myClock1.display();
    
    Clock myClock2(8, 3, 30);	// 定义对象,此时自动调用有参构造函数
    cout << "利用有参构造函数创建的时间对象为:";
    myClock2.display();
    
    myClock2.setHour(21);
    cout << "修改过的对象的时间为:";
    myClock2.display();    
    
    return 0;
}
二、数据域封装
2.1 数据封装的方法
-  在定义私有数据域的类之外,对象不能通过直接引用访问该数据域 // 这两种方式均错误 myClock.hour = 5; hour = myClock.hour;
-  为了能够访问私有数据域,可以编写一个成员函数返回数据值(如getHour,getMinute),为了能够修改它,可以编写一个成员函数(如setHour,setMinute)进行设置 myClock.setHour(5); hour = myClock.getHour();
2.2 数据封装的优点
2.2.1 防止对封装数据的越权访问
- 如果要隐藏studentID域,实现数据域的保护的方法有: 
  - 用private声明这个数据
- 不要定义getStudentID函数
 
class Student {
private:
    char studentID[20];
    char studentName[20];
    ......
}
2.2.2 限制私有特性改变时产生的连锁反应
- 属性是私有的,不对外公开,必须要通过getAge函数去读取私有属性(age)的内容
- 一个信息被隐藏的越好,未来可被修改的权利就更大
// 修改前的代码
class Student {
// 定义了age属性
private:
    int age;
public:
    int getAge(){
        return age;
    }
    ...
}
// 修改后的代码
// 把age属性替换成出生年、月、日
class Student {
private:
    int birthYear;
    int birthMonth;
    int birthDate;
public:
    int getAge(){
        age = 系统时间 - 出生年、月、日
        return age;
    }
    ...
}
// 调用代码
// 修改前后调用代码不需要改变
Student s;
int currentAge = s.getAge();
 
 
2.2.3 保持数据的完整性
/* 
birthdate是私有属性
外界可以修改birthdate,但是数据的格式必须要符合要求,比如mm/dd/yyyy这种,因此可定义一个共有的检查函数updateBirthdate()
先对传过来的新修改的birthdate值进行格式检查,只有当格式符合要求的时候才可以调用私有成员函数setBirthdate()对birthdate进行修改
*/
class Student {
private:
    char birthdate[12];
    void setBirthdate(char d[]) {
        strcpy(birthdate, d);
    }
public:
    bool updateBirthdate(char d[]) {
        if(Data format is not mm/dd/yyyy)
            return false;
        else if(range of mm or dd is wrong)
            return false;
        else{
            setBirthdate(d);
            return true;
        }
    }
};
 
                


















