基类的虚函数在派生类中再定义称为函数的“覆盖(overriding)”,与“重载(overload)”是不同的2个概念,不要混淆。重载对类适用,对普通函数也适用,重载函数的参数一定是不相同的。覆盖只适用于类,并且是基类与派生类之间的重定义,其参数甚至返回值必须完全相同。
虚函数或纯虚函数自身并不实现任何功能,各个不同的类在继承时才实现不同的功能,因此,同一个虚函数在执行时具有了多种不同功能,称之为“多态”。
小雅以前在为单位面试新人时,有很多人对面向对象还很模糊,便自称精通C++,这是不可取的。理解了类、抽象类的思想还只能算入门,只有在不断实践中掌握更多的设计方法以及各种设计Pattern,才能算真正的C++程序员。
因这部分内容比较重要,本章不介绍新内容,只举例来加深理解。
基类里定义三个函数:设置区域数据setData()、取区域数据getData、求面积(虚函数)getArea。所谓数据,定义2个成员变量dim1和dim2,对于长方形来说是长和宽,对于三角形来说是底和高。
设计2个派生类,1个是长方形rectangle、1个是三角形triangle。要点是对getArea函数实装。
![]()
#include<iostream>using namespacestd;classarea {doubledim1, dim2;public: //设置数据voidsetData(doubled1,doubled2) { dim1 = d1, dim2 = d2; } //取数据voidgetData(double& d1,double& d2) { d1 = dim1, d2 = dim2; } //求面积virtual doublegetArea() = 0; //纯虚函数 }; //长方形classrectangle :publicarea {public:doublegetArea() {doubled1, d2; getData(d1, d2);returnd1 * d2 ; } }; //三角形classtriangle :publicarea {public:doublegetArea() {doubled1, d2; getData(d1, d2);returnd1 * d2 / 2 ; } };intmain ( ) { area *p; rectangle r; //长方形类的实例 triangle t; //三角形类的实例 r.setData(35, 44); t.setData(36, 25); p = &r; cout << "长方形的面积为: " << p->getArea() << endl; p = &t; cout << "三角形的面积为: " << p->getArea() << endl;return0; }
队列和堆栈都是链表类型(可以参考“C语言教程”中的22章),它和数组不同的是个数是不定的,因此必须用指针来“记住”开始、末尾和下一个的位置。因此基类中有三个指针head、tail、next成员变量。还有一个成员变量num用来表示当前插入的值。另外定义2个纯虚函数store()和retrieve()来表示存贮(即增加)一个元素、处理(减少)一个元素,这是要编程的要点。
派生类里面要实现2个功能,即增加节点、删除节点。增加时首先new一个节点并对num赋值,然后修改链表的三个指针。而删除时要先修改链表的三个指针,然后再删除节点。
队列和堆栈的不同处是:队列是先进先出、后进后出;而堆栈则是先进后出、后进先出。这就是修改三个链表指针时要注意的地方。这需要有一点数据结构方面的知识。
![]()
#include<iostream>#include<cstdlib>#include<cctype>using namespacestd;classlist {public: list *head; //头指针 list *tail; //尾指针 list *next; //下一个指针intnum; //当前节点的值 list() { head = tail = next = NULL; } //构造函数virtual voidstore(inti) = 0; //增加节点virtual intretrive() = 0; //删除节点 }; //队列classqueue :publiclist {public: //增加节点virtual voidstore(inti) { list *item =newqueue;if(!item) { cout << "内存分配失败!" << endl; exit(1); } item->num = i; //链表末尾插入if(tail) tail->next = item; tail = item; item->next = NULL;if(!head) head = tail; } //取值并删除节点intretrive() {inti; list *p;if(!head) { cout << "链表已经为空" << endl;return0; } //从链表头部删除 i = head->num; p = head; head = head->next;deletep;returni; } }; //堆栈classstack :publiclist {public: //增加节点virtual voidstore(inti) { list *item =newstack;if(!item) { cout << "内存分配失败!" << endl; exit(1); } item->num = i; //链表头部插入if(head) item->next = head; head = item;if(!tail) tail = head; } //取值并删除节点intretrive() {inti; list *p;if(!head) { cout << "链表已经为空" << endl;return0; } //从链表头部删除 i = head->num; p = head; head = head->next;deletep;returni; } };intmain ( ) { list *p; //队列的演示 queue q; p = &q; p->store(111), p->store(222), p->store(333); cout << "队列: "; cout << p->retrive() << " "; cout << p->retrive() << " "; cout << p->retrive() << endl; //堆栈的演示 stack s; p = &s; p->store(111), p->store(222), p->store(333); cout << "堆栈: "; cout << p->retrive() << " "; cout << p->retrive() << " "; cout << p->retrive() << endl;return0; }