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