第三课类和对象 ( 封装 ) 互联网新技术在线教育领航者 1
内容概述 1. 封装的概念 2. 访问控制 3. 栈类的封装 4. 构造与析构 5.myString 构造函数 6. 构造与析构的次序 7. 类文件写法 8. 对象的内存 9.this 指针初探 10. 构造函数初始值列表 11. 拷贝构造和赋值运算符重载 12. 浅拷贝 13. 深拷贝 14. 成员函数内联 15. 友元 16.const 和 static 成员 17. 单例模式 18. 类类型隐式转换 19. 类类型传参和返回值 20. 练习 :mylist 链表 互联网新技术在线教育领航者 2
封装 类的基本思想 : 数据抽象和封装 数据抽象是一种依赖于接口和实现分离的编程技术 接口 : 类的用户所能执行的操作实现 : 类的数据成员 接口函数的实现及其他私有函数的实现封装 : 实现了类的接口和实现的分离 封装后的类隐藏了实现细节 ; 类的用户只能使用接口而无法访问实现部分 面向对象三大特性 : 封装 继承 多态 互联网新技术在线教育领航者 3
访问控制 struct 结构体 结构体变量 class 类 对象 1. 数据与行为不分离 ( 成员变量, 成员函数 ) 2. 权限控制 : 类内开放, 类外控制保证数据完整性 正确性 3. 成员函数, 调用内部变量不需要传参 访问说明符 : public: 公共的 protected: 保护的 private: 私有的 C++ 中,class 和 struct 没有本质区别, 只是默认权限不同 互联网新技术在线教育领航者 4
栈类 权限控制的重要性提供的接口 : isempty(), isfull(), init(), destroy(), top(), push(), pop() 成员函数 const 互联网新技术在线教育领航者 5
构造函数 析构函数 构造函数 : 每个类都定义了它的对象被初始化的方式, 类通过一个或多个特殊的成员函数来控制其对象的初始化 ( 生成对象时自动调用 ) 析构函数 : 释放对象使用的资源 ( 对象销毁时自动调用 ) 构造函数 : 与类名相同, 无返回, 可以有参数析构函数 :~ 与类名相同, 无参数, 无返回 互联网新技术在线教育领航者 6
构造函数初步 1. 可以有参数, 有默认参数, 可以重载 2. 若未提供构造函数, 系统默认生成一个无参空构造若提供, 则不再生成默认无参空构造函数类名 a; // 调用无参构造 [ 不能写成类名 a(), 编译器会认为是函数声明 ] 类名 a(xx); // 调用有参构造 a{xx} 也可以 通过 new 在堆空间创建对象, 同样会自动调用构造函数 互联网新技术在线教育领航者 7
构造函数初步 :mystring 类的构造函数 思考 :string 类是怎么实现的? 模仿标准库的 string 类 : string s1; // 无参构造 string s2( abc ) // 有参构造 互联网新技术在线教育领航者 8
析构函数初步 析构函数 : 释放对象使用的资源 ( 对象销毁时自动调用 ) 1. 无参, 无返回 ( 不可重载 ) 2. 若未提供, 系统默认生成一个空析构函数 通过 delete 销毁堆空间上的对象, 同样会自动调用析构 设计原则 : 自己申请的资源, 自己负责释放 互联网新技术在线教育领航者 9
构造与析构 : 次序 1. 多个对象, 按次序构造, 析构次序相反 2. 类中有成员变量也是类对象的时候, 先运行成员类的构造函数, 再运行本类的构造函数 析构次序与构造次序相反 3. 注意类中成员变量是类的指针类型的话, 不会调用构造函数 互联网新技术在线教育领航者 10
构造与析构 : 次序 1. 栈空间中的对象脱离作用域时, 析构 2. 堆空间中的对象 delete 时, 析构 互联网新技术在线教育领航者 11
类文件写法 通常将一个类分为 2 个文件 : 类的声明写在类名.h 类的实现写在类名.cpp 一个类就是一个作用域 在类的外部定义成员函数时 : 返回值类型类名 :: 函数名 ( 参数 ) 互联网新技术在线教育领航者 12
对象的内存 类 对象, 模具 产品 创建对象时 : 只有成员变量开辟内存 没有成员变量时, 占 1 个字节 成员函数并不占用对象的空间 class 中的成员变量和 C 中的 struct 一样, 要对齐 补齐 互联网新技术在线教育领航者 13
this 指针初探 This 指针可认为是顶层 const, 不能修改 this = xxx; 错误 互联网新技术在线教育领航者 14
构造函数初始值列表 有些类中, 初始化和赋值的区别事关低层效率的问题 初始化的先后次序, 与成员变量出现的先后次序一致 互联网新技术在线教育领航者 15
拷贝构造和赋值运算符重载 拷贝构造函数 : class 类名 { 类名 (const 类名 & another); } 1. 系统提供默认的拷贝构造, 若自己提供, 则不复存在 2. 默认拷贝构造是等位拷贝, 也就是所谓的浅拷贝 3 要实现深拷贝, 必须要自己实现 赋值运算符重载 : 类名 { 类名 & operator=(const 类名 & 源对象 ) ; return *this; } 与拷贝构造类似 互联网新技术在线教育领航者 16
浅拷贝 浅拷贝可能会造成内存泄漏 重析构 互联网新技术在线教育领航者 17
深拷贝实现 赋值运算符重载 : 要注意自己给自己赋值的情况 互联网新技术在线教育领航者 18
成员函数内联 内联函数 :inline 修饰, 编译时展开 互联网新技术在线教育领航者 19
友元 封装 : 类的数据成员一般定义为私有成员, 外部要访问类的私有成员只能通过接口 ( 如 get,set 方法 ) 特殊情况 : 类外有些函数需要频繁地访问类的数据成员, 此时可以将这些函数定义为该类的友元函数 友元的好处 : 提高了程序的运行效率 ( 减少类型和安全性检查及调用的时间开销 ) 友元的副作用 : 破坏了类的封装性和隐藏性, 使得非成员函数可以直接访问类的私有成员 友元可以是一个函数, 称为友元函数 ; 友元也可以是一个类, 称为友元类 互联网新技术在线教育领航者 20
友元 同类之间可直接访问 例 :A(const A &other) { num = other.num; } 全局函数 类成员函数可作为友元函数 类的所有成员函数都可直接访问 : 友元类 互联网新技术在线教育领航者 21
友元 (1) 友元关系不能被继承 (2) 友元关系是单向的, 不具有交换性 若 B 是 A 的友元, A 不一定是 B 的友元 (3) 友元关系不具有传递性 若 B 是 A 的友元, C 是 B 的友元, 不能推出 C 是 A 的友元 互联网新技术在线教育领航者 22
类的 const 常量成员 const 成员变量, 不能修改, 只能在初始值列表中初始化 const 成员函数 : 1. const 放在函数声明之后, 实现体之前 void fun()const { } 2. 承诺在本函数内部不会修改类内的数据成员, 不会调用其它非 const 成员函数 3. const 构成函数重载 (why? this 指针底层 const) const 对象, 只能调用 const 成员函数 可访问所有数据成员, 不可修改 互联网新技术在线教育领航者 23
类的 static 静态成员 static 成员变量 : 同类对象间信息共享, 类外存储, 必须类外初始化, 可通过类名访问, 也可通过对象访问 静态成员函数 : 管理静态数据成员, 对静态数据成员封装 ( 对外提供接口 ) 静态成员函数 : 只能访问静态数据成员 静态成员函数属于类, 没有 this 指针 互联网新技术在线教育领航者 24
单例模式 1. 将默认构造函数和析构函数声明为私有, 外部无法创建, 无法销毁 ( 只能自己销毁自己 ) 2. 使用一个私有的静态本类类型的指针变量, 用来指向该类的唯一实例 3. 用一个公有的静态方法来获取该实例, 第一次调用该方法时, 创建实例并返回 ( 懒汉式 ), 以后调用直接返回 4. 用一个公有的静态方法来删除该实例, 以保证该实例只会被删除一次 互联网新技术在线教育领航者 25
类类型隐式转换 互联网新技术在线教育领航者 26
类类型临时量 类类型临时量, 在表达式结束后自动析构 互联网新技术在线教育领航者 27
类类型传参 互联网新技术在线教育领航者 28
类类型返回值 互联网新技术在线教育领航者 29
练习 :mylist 链表 1 实现一个链表类 : 1. 带头结点 2. 数据类型是 Student 类, 学号起始编号是 100 3. 实现下列功能 : mylist(const mylist& other); // 深拷贝构造 mylist &operator=(const mylist& other); // 赋值重载 void insert_tail(int _age,const string& _name); // 尾插 bool del_node(int _id); // 按 id 删除节点 void print()const; // 遍历打印 inline int get_size()const; // 获取链表中元素个数 互联网新技术在线教育领航者 30
练习 :mylist 链表 2 Student_Node 类 ( 结点 ): 1. 学号自动增长 static 静态变量和静态函数 2. Student_Node 类没有实现析构 拷贝构造 赋值运算符重载, 可行吗? 3. 假如学员姓名用自己写的 mystring 类, 那么要在哪里自己实现上面的那些函数? 4. 声明了 mylist 是 Student_Node 的友元类, 假如不允许使用友元, 该类还需要提供哪些函数? 互联网新技术在线教育领航者 31
练习 :mylist 链表 3 mylist 类 : 1. 内联函数为啥写在 mylist.h 头文件中? 2. 链表要求带头结点, 构造函数怎么写? 3. 拷贝构造函数和赋值运算符重载实现上有什么区别? 4. 要如何析构 mylist? 互联网新技术在线教育领航者 32
练习 :mylist 链表 4 互联网新技术在线教育领航者 33
练习 :mylist 链表 5 互联网新技术在线教育领航者 34
练习 :mylist 链表 6 mylist 其他函数 : insert_tail : 尾插 del_node : 根据学号删除 互联网新技术在线教育领航者 35
练习 :mylist 链表 7 互联网新技术在线教育领航者 36