上岸充通大 1896 006 C++程序设计与实践 第7讲C++类(2) 上海交通大学 漏 机械与动力工程学院 2014.9-2015.1 上泽充通大¥ 1896 1920 1. 类的多态性 2.标准库vector类的使用 3.标准库string类的使用 4.面向对象的程序设计 SH 1
1 C++程序设计与实践 上海交通大学 机械与动力工程学院 2014.9-2015.1 第7讲 C++类(2) 1. 类的多态性 2. 标准库vector类的使用 3. 标准库string 类的使用 4. 面向对象的程序设计 5. 类的使用
多个闹钟的管理 1 2 3 1115 4、 > Clock 闪烁 Alarm() 闹声 闹声 振动 国上清夫道大些 3/30 多个闹钟的管理 闹钟功能 子类 DigitalClock Alarm() 振动 父类 Clock AuditoryClock Alarm() 闹声 Alarm() Clock *cl1 new DigitalClock; AnalogClock 闪烁 cl1->Alarm(); Alarm( 根据函数名和参数无法确定应该调用哪一个函数,必须在程序 的执行过程中,根据具体的执行情况来动态地确定 圈上海大大学 4/30 2
2 3/30 多个闹钟的管理 Clock Alarm() 振动 闹声 闪烁 闹声 4/30 多个闹钟的管理 闹钟功能 根据函数名和参数无法确定应该调用哪一个函数,必须在程序 的执行过程中,根据具体的执行情况来动态地确定 Clock Alarm() AnalogClock Alarm() DigitalClock Alarm() Clock *cl1 = new DigitalClock; 父类 cl1->Alarm(); ? 子类 振动 闹声 闪烁 AuditoryClock Alarm()
继承法 Clock 什么都不做 任务: Alarm() 批量实现不同时钟的闹钟动作 多个类:AnalogClock,DigitalClock 首先判断是属于什么时钟,才能调用 AnalogClock DigitalClock 相应的Alaram()函数 Alarm() Alarm() Clock clock1; DigitalClock c1; clock1.Alarm(; Clock *pc1=&c1; 闪烁 振动 pc1->Alarm(); DigitalClock c1; Clock *p1=&c1; 实际调用的是Clock类中 p1->Alarm(); Alarm( 图上清夫道大学 530 继承法 class Clock public: ClockO void Alarm(void)coutAlarm () 输出:Clock Alarm! } 国上海文大华 630 3
3 5/30 继承法 Clock Alarm() AnalogClock Alarm() DigitalClock Alarm() 任务: 批量实现不同时钟的闹钟动作 首先判断是属于什么时钟,才能调用 相应的Alaram()函数 多个类:AnalogClock, DigitalClock Clock clock1; clock1.Alarm(); DigitalClock c1; Clock *pc1=&c1; 闪烁 振动 pc1->Alarm(); 什么都不做 实际调用的是? Clock类中 Alarm() DigitalClock c1; Clock *p1=&c1; p1->Alarm(); 6/30 class Clock {public: Clock(){} void Alarm(void){coutAlarm (); } 输出:Clock Alarm! 继承 继承法
虚函数 Clock DigitalClock d1; virtual Alarm() AnalogClock a1; Clock *p1=&d1; p1->Alarm(); p1=&a1; AnalogClock DigitalClock p1->Alarm(); Alarm() Alarm() virtual FuncName(); 调用AnalogClock类和 通过基类指针调用派生类函数 DigitalClock类中Alarm0 for (int i=0;iAlarm(; 国上清夫道大些 730 虚函数 class Clock public: Clock() virtual void Alarm()coutAlarm O; 输出:DigitalAlarm! Alarm(声明为虚函数,使派生类与基类的Alarm0函数有一个统一的接口 4
4 7/30 虚函数 Clock virtual Alarm() AnalogClock Alarm() DigitalClock Alarm() 调 用 AnalogClock 类 和 DigitalClock类中Alarm() DigitalClock d1; AnalogClock a1; Clock *p1=&d1; p1->Alarm(); p1=&a1; p1->Alarm(); virtual FuncName(); 通过基类指针调用派生类函数 for (int i=0; iAlarm(); 8/30 虚函数 class Clock {public: Clock(){} }; class DigitalClock: public Clock {public: DigitalClock(){} void Alarm( ){coutAlarm (); } 派生类定义 调用虚函数 Alarm()声明为虚函数,使派生类与基类的Alarm ()函数有一个统一的接口 virtual void Alarm( ){cout<<“Clock Alarm!”<<endl;} //声明为虚函数 继承 输出:DigitalAlarm! 用基类指针调用派生类函数
虚析构函数 Clock virtual ~Clock() Clock *p=new DigtialClock; delete p; AnalogClock DigitalClock 0 ~AnalogClock() -DigitalClock() 实际执行~Clock(); DigitalClockO ClockO *hour=new int;) “清理现场”不干净 } ~DigitalClockO ~Clock() 实际先执行 if(hour!=NULL) ~DigitalClock(), delete hour; hour=NULL;} 再执行~Clock0 先调用派生类的析构函数,再调用基类的析构函数 网上海家大学 91/30 练习1 1. 基类析构函数输出“executing Clock destructor'” 2. 派生类DigitalClock的构造函数用new创建一个double类型的指针变 量hour,析构函数delete这个hour变量并输出“executing DigitalClock destructor" 3. 在main函数中创建DigitalClock变量的指针,并调用虚析构函数 Clock main函数: -Clock() Clock *p new DigitalClock; A delete p; DigitalClock 0 +hour:double +DigitalClock() executing AnalogClock destructor ~DigitalClock() executing DigitalClock destructor 国上海大学 10/30 5
5 9/30 虚析构函数 AnalogClock ~AnalogClock() DigitalClock ~DigitalClock() 实际执行~Clock(); Clock *p=new DigtialClock; delete p; “清理现场”不干净 实际先执行 ~DigitalClock(), 再执行~Clock() 先调用派生类的析构函数,再调用基类的析构函数 Clock ~Clock() DigitalClock() { *hour = new int;} ~DigitalClock() { if(hour != NULL) {delete hour; hour = NULL;} } Clock() { } ~Clock() { } Clock virtual ~Clock() 10/30 1. 基类析构函数输出“executing Clock destructor” 2. 派生类DigitalClock的构造函数用new创建一个double类型的指针变 量 hour ,析构函数 delete 这 个 hour 变量并输出“ executing DigitalClock destructor” 3. 在main函数中创建DigitalClock变量的指针,并调用虚析构函数 executing AnalogClock destructor executing DigitalClock destructor 练习1 main函数: Clock *p = new DigitalClock; delete p;
练习1 class Clock (public:Clock() virtual ~Clock(){cout<<"executing Clock destructor"<<endl;} →声明为虚析构函数 class DigitalClock:public Clock public: double *hour: DigitalClock((hour=new double; DigitalClock类析构函数 -DigitalClockO) delete hour: cout<<"executing DigitalClock destructor"<<endl;} int main(void) Clock *p=new DigitalClock; /∥用new开辟动态存储空间 deletep; 动态调用虚析构函数 executing DigitalClock destructor executing Clock destructor 人守 11/30 多态的优点 1. 应用程序不必为每一个派生类编写功能调用,只需要对抽 象基类进行处理即可。这一招叫“以不变应万变”,可以 大大提高程序的可复用性(这是接口设计的复用,而不是 代码实现的复用)。 2.派生类的功能可以被基类指针引用,这叫向后兼容,可以 提高程序的可扩充性和可维护性。以前写的程序可以被将 来写的程序调用不足为奇,但是将来写的程序可以被以前 写的程序调用那可了不起。 国上海大学 12/30 6
6 11/30 class Clock {public: Clock(){} ~Clock (){ cout<<“executing Clock destructor”<<endl; } }; class DigitalClock: public Clock {public: double *hour; DigitalClock(){hour=new double;} ~DigitalClock() { delete hour; cout<<“executing DigitalClock destructor”<<endl; } }; int main(void) { Clock *p = new DigitalClock; //用new开辟动态存储空间 delete p; return 0;} executing Clock destructor 声明为虚析构函数 DigitalClock类析构函数 executing DigitalClock destructor executing Clock destructor virtual ~ Clock() { cout<<“executing Clock destructor”<<endl; } 动态调用虚析构函数 练习1 12/30 多态的优点 1. 应用程序不必为每一个派生类编写功能调用,只需要对抽 象基类进行处理即可。这一招叫“以不变应万变”,可以 大大提高程序的可复用性(这是接口设计的复用,而不是 代码实现的复用)。 2. 派生类的功能可以被基类指针引用,这叫向后兼容,可以 提高程序的可扩充性和可维护性。以前写的程序可以被将 来写的程序调用不足为奇,但是将来写的程序可以被以前 写的程序调用那可了不起
上岸充通大 1896 1920 1.类的多态性 2. 标准库vector类的使用 3. 标准库string类的使用 4.面向对象的程序设计 标准库vector类的使用 C+提供了封装了数组操作的类,常用操作函数:元素增加、 元素个数、引用、删除, #include 为了在程序中使用vector类型,必须包含 #include vector头文件 using namespace std; 定义:vectora; V.S int a[10]; v.push back(elem) 在v的末尾增加一个值为clem的元素 v.size() 返回v中实际元素的个数 v[index] 返回v中索引为index的元素 v.pop_back() 删除最后一个数据 国上济大学 14/30 7
7 1. 类的多态性 2. 标准库vector类的使用 3. 标准库string 类的使用 4. 面向对象的程序设计 5. 类的使用 14/30 标准库vector类的使用 #include #include using namespace std; 为了在程序中使用vector类型,必须包含 vector头文件 v.push_back(elem) 在v的末尾增加一个值为elem的元素 v.size( ) 返回v中实际元素的个数 v[index] 返回v中索引为index的元素 v.pop_back( ) 删除最后一个数据 C++提供了封装了数组操作的类,常用操作函数:元素增加、 元素个数、引用、删除,…… 定义: vector a; V.S int a[10];
标准库vector类的使用 #include v.push_back(elem) 在v的末尾增加一个值为 #include clem的元素 using namespace std; v.size() 返回v中实际元素的个数 main() v[index] 返回v中索引为index的元素 v.pop back() 副除最后一个数据 vector v1: v1.push_back(1); v1.push_back(2); int index_last v1.size()-1; cout <<"Last element:"<v1[index_last]<endl; Output Last element:1 v1.pop_back(); New last element:2 index_last=v1.size()-1; cout <<"New last element:"<v1[index_last]<endl; 国上海文大等 15/30 上究通大粤 1896 1920 1. 类的多态性 2. 标准库vector类的使用 3.标准库string类的使用 4.面向对象的程序设计 8
8 15/30 标准库vector类的使用 vector v1; v1.push_back( 1 ); v1.push_back( 2 ); int index_last = v1.size()-1; cout #include using namespace std; main( ) Output Last element: 1 New last element: 2 v.push_back(elem) 在v的末尾增加一个值为 elem的元素 v.size( ) 返回v中实际元素的个数 v[index] 返回v中索引为index的元素 v.pop_back( ) 删除最后一个数据 1. 类的多态性 2. 标准库vector类的使用 3. 标准库string 类的使用 4. 面向对象的程序设计 5. 类的使用
圈上支大学 标准库string类的使用 #include 为了在程序中使用vector类型,必须包含 #include string头文件 using namespace std; main() s.sizc()、s.length()返回s中字符的个数 字符串赋值 string str1("Hello world"); cout、>=、 按字典序比较字符串 字符串赋值 s.erase() 清空字符申 s1+s2 把s1和s2连接成一个新字符串,返回新生成的字符申 +=、s.append() 在尾部添加字符 s、satn) 存取s中位置为的字符,位置从0开始计数 find() 子串查找 s.insert() 插入字符 s.replace() 字符串誉换 s.swap() 交换两个字符串的内容 >、getline() 从stream读取某值 18/30 9
9 17/30 标准库string类的使用 string str1 ("Hello world"); cout #include using namespace std; 为了在程序中使用vector类型,必须包含 string头文件 main( ) Output The original string str1 is: Hello world The modified string str1 is: Hello The appended string str1 is: Hello C++ s.size( )、s.length( ) 返回s中字符的个数 = 字符串赋值 s.erase( ) 清空字符串 s.append( ) 在尾部添加字符 18/30 string 类操作 s.size( )、s.length( ) 返回s中字符的个数 s.empty( ) 如果s为空串,则返回true,否则返回false s.max_size( ) 返回字符的可能最大个数 s.capacity( ) 返回重新分配之前的字符容量 s.reserve( ) 保留一定量内存以容纳一定数量的字符 ==、!=、、>=、 按字典序比较字符串 = 字符串赋值 s.erase( ) 清空字符串 s1 + s2 把s1和s2连接成一个新字符串,返回新生成的字符串 +=、s.append( ) 在尾部添加字符 s[n]、s.at(n) 存取s中位置为n的字符,位置从0开始计数 find( ) 子串查找 s.insert( ) 插入字符 s.replace( ) 字符串替换 s.swap( ) 交换两个字符串的内容 >>、getline( ) 从stream读取某值
上岸充通大 1896 1920 1987 7006 1. 类的多态性 2.标准库vector类的使用 3. 标准库string类的使用 4.面向对象的程序设计 继承设计规则 1. C+的“继承”特性可以提高程序的可复用性。 2. 如果类A和类B毫不相关,不可以为了使B的功能更多些而让 B继承A的功能。 3.如果类B有必要使用A的功能,则要分两种情况考虑: a 若在逻辑上B是A的“一种”(a kind of),则允许B继 承A的功能。例如男人(Man)是人(Human)的一种, 男孩(Boy)是男人的一种。那么类Man可以从类Human 派生,类Boy可以从类Man派生。 b)若在逻辑上A是B的“一部分”(a part of),则不允许B 继承A的功能,而是要用A和其它东西组合出B。例如眼 (Eye)、鼻(Nose)、口(Mouth)、耳(Ear)是头 (Head)的一部分,所以类Head应该由类Eye、Nose、 Mouth、Ear组合而成,不是派生而成。 国上海大峰 20/30 10
10 1. 类的多态性 2. 标准库vector类的使用 3. 标准库string 类的使用 4. 面向对象的程序设计 5. 类的使用 20/30 继承设计规则 1. C++的“继承”特性可以提高程序的可复用性。 2. 如果类A和类B毫不相关,不可以为了使B的功能更多些而让 B继承A的功能。 3. 如果类B有必要使用A的功能,则要分两种情况考虑: a) 若在逻辑上B是A的“一种”(a kind of ),则允许B继 承A的功能。例如男人(Man)是人(Human)的一种, 男孩(Boy)是男人的一种。那么类Man可以从类Human 派生,类Boy可以从类Man派生。 b) 若在逻辑上A是B的“一部分”(a part of),则不允许B 继承A的功能,而是要用A和其它东西组合出B。例如眼 (Eye)、鼻(Nose)、口(Mouth)、耳(Ear)是头 (Head)的一部分,所以类Head应该由类Eye、Nose、 Mouth、Ear组合而成,不是派生而成