第四章 类与对象
面向对象程序设计的基本特点
-
抽象
- 对同一类对象的共同属性和行为进行概括,形成类。
- 先注意问题的本质及描述,其次是实现过程或细节。
- 数据抽象:描述某类对象的属性或状态(对象相互区别的物理量)。
- 代码抽象:描述某类对象的共有的行为特征或具有的功能。
- 抽象的实现:类。
- 抽象实例:钟表
- 数据抽象:int hour, int minute, int second;
- 代码抽象:setTime(), showTime()。
class Clock { public: void setTime(int newH, int newM, int newS); void showTime(); private: int hour, int minute, int second; };
- 对同一类对象的共同属性和行为进行概括,形成类。
-
封装
- 将抽象出的数据、代码封装在一起,形成类。
- 目的:增强安全性和简化编程,使用者不必了解具体的实现细节,而只需要通过外部接口,以特定的访问权限,来使用类的成员。
- 实现封装:类声明中的{}。
-
继承
- 在已有类的基础上,进行扩展形成新的类。
-
多态
- 多态:同一名称,不同的功能实现方式。
- 目的:达到行为标识统一,减少程序中标识符的个数。
- 实现:重载函数和虚函数。
类和对象
类和对象的定义
-
对象是现实中的对象在程序中的模拟。
-
类是同一类对象的抽象,对象时类的某一特定实体。我们对同类型的对象进行概括,进行抽象,就形成了类。
-
对象是类的实例,定义类的对象,才可以通过对象使用类中定义的功能。
-
设计类就是设计类型。
- 首先我们要关心这个类型的合法值是什么,这个类型应该有什么样的函数,有什么样的操作符;
- 其次我们还要定义新类型的对象,它如何被创建,如何被销毁,还有对象怎么进行初始化和赋值;
- 还有对象也应该可以作为函数的参数进行传递的,那么我们如何把对象作为函数的参数进行传递也是我们在定义类的时候应该关注的问题;
- 最后我们要清楚谁将使用这个类型的对象还有它的对象的成员。
-
类定义的语法形式
-
定义类的语法形式要用关键字 class 开头,后面就是类名称即这个类的一个标志符;
-
在这一对大括号里面有类的成员,这个类的成员又分成公有成员、私有成员和保护成员,不管是数据成员还是函数成员都可以分成这样三类;
-
类里面的属性是用数据成员表示的,类里面的功能是用函数成员表示的;
-
我们在定义类的时候还可以给类的数据成员指定类内的初始值,这个类内的初始值是在构造对象的时候用于初始化对象用的,如果有构造函数
对它进行初始化,就会按照构造函数指定的值进行初始化,如果构造函数没有对数据成员进行初始化,那么就会用这个类内的初始值;class Clock { public: void setTime(int newH, int newM, int newS); void showTime(); private: int hour = 0, minute = 0, second = 0; };
-
-
类的成员分成公有成员、私有成员和保护成员三种访问控制属性:
- 公有成员
- 公有成员就是在关键字 public 后面声明的成员
- 公有成员是一个类与外部的接口,任何外部函数都可以访问类的共有数据和共有函数;
- 私有成员
- 私有成员是在关键字 private 后面声明的:
- 私有成员是对外屏蔽了,在外面看不见一个类的私有成员,所以私有成员只允许本类中的函数来访问,类外部的任何函数都不能访问一个类的私有成员,我们可以用友元授权类外的函数访问私有成员;
- 如果我们在定义类的成员的时候紧跟着类名之后的那个大括号就声明成员,那么这个时候如果不写任何访问控制属性的关键字默认的话这个成员是私有成员;
- 如果你在类体的最开头定义私有成员的话,那么这个 private 关键字它是可以省略的。
- 保护成员
- 保护成员看起来与私有成员很像;
- 保护成员与私有成员的差别是在继承和派生的时候才看得出来。
class 类名称{ public: 公有成员(外部接口) private: 私有成员 protected: 保护型成员 }; ```
- 公有成员
-
当我们定义好一个类以后,通常我们都要定义一个对象,然后通过对象去调用它的成员函数,这样来使用类的功能。
-
对象定义的语法
- 对象定义的语法是这样的,首先前面是类名,然后后面跟个对象名;
- 类名 对象名;
- 例:Clock myClock;
-
类成员的访问权限
- 类中成员互相访问
- 直接使用成员名访问。
- 类外访问
- 使用“对象名.成员名”方式访问 public 属性的成员。
- 类中成员互相访问
-
类的成员函数
- 在类中说明函数原型;
- 可以在类外给出函数体实现,并在函数名前使用类名加以限定,实现这个函数的时候跟我们定义普通的函数唯一一个区别就是在函数名前面要使用类名来加以限定,也就是说,这个函数它不是一个普通的全局函数,要说明它是属于哪个类的成员函数;
- 也可以直接在类中给出函数体,形成内联成员函数,内联的成员函数必须充分简单;
- 在类里面声明成员函数的时候,同样也允许声明重载函数和带默认参数值的函数。
-
内联成员函数
- 为了提高运行时的效率,对于较简单的函数可以声明为内联形式。
- 内联函数体中不要有复杂结构(如循环语句和switch语句)。
- 在类中声明内联成员函数的方式:
- 将函数体放在类的声明中,就是把函数体直接写在类的类体中;
- 使用 inline 关键字,就是在类体中只声明函数的原型,然后在类外实现函数,只不过实现函数体的时候要用 inline 关键字。
类和对象程序举例
- 钟表类
- 首先我们来看这个钟表类的定义,
- 这个类里面分装了两个函数:
- setTime:设置时间
- showTime:显示时间
- 还有这三个数据成员,它表示小时、分、秒;
- 这个 setTime 的三个参数都设置了默认值,也就是说,当我们调用setTime的时候
如果给了实参,那么就用实参值,如果说实参没有给或者没有给够,就会用这里面设置的默认参数值;
- 这个类里面分装了两个函数:
- 接下来我们再来看成员函数的实现:
- 实现一个成员函数跟实现一个普通函数其实是很像的,差别在于要写上类名和作用域限定符,也就是说,这个 setTime 函数,这个 showTime 函数不是一般的全局函数,它是 Clock 类里面的成员函数,所以要把类名写在前面;
- 这个 setTime 的功能就是将这几个形参的值复制给当前这个对象的小时、分、秒三个数据成员;
- 这个showTime呢就是将这个小时分秒 hour minute second 显示出来送到显示器上去。
- 现在在主函数中我们要使用这个类
- 需要定义一个 Clock 类的对象 myClock,因为我们不能直接去使用类的设计,要使用一个类就得用它的对象,用它的实例,所以在这儿定义了一个 Clock 类的实例即myClock 这样一个对象;
- 然后我们的程序就可以跟 myClock 这个对象进行通信了。
// 第一种写法 #include "pch.h" #include <iostream> using namespace std; // 类的定义 class Clock { public: void setTime(int newH = 0, int newM = 0, int newS = 0); void showTime(); private: int hour, minute, second; }; // 成员函数的实现 void Clock::setTime(int newH, int newM, int newS) { hour = newH; minute = newM; second = newS; } void Clock::showTime() { cout << hour << ":" << minute << ":" << second; } // 对象的使用 int main() { Clock myClock; myClock.setTime(8, 30, 30); myClock.showTime(); return 0; }
// 第二种写法 #include "pch.h" #include <iostream> using namespace std; class Clock { int hour, minute, second; // 默认为私有成员 public: // 内联函数在类内不需要加类名 Clock void setTime(int newH = 0, int newM = 0, int newS = 0) { hour = newH; minute = newM; second = newS; } void showTime() { cout << hour << ":" << minute << ":" << second; } }; int main() { Clock myclock; myclock.setTime(8, 30, 30); myclock.showTime(); return 0; }
- 首先我们来看这个钟表类的定义,