采用纯虚函数实现多态性来建立通用的双向链表派生类。
解:
#include<iostream>
using namespace std;
//首先看结点组织,采用结点类加数据类
class Object{//数据类为抽象类
public:
Object(){}
virtual bool operator>(Object &)=0;//纯虚函数,参数必须为引用或指针
virtual bool operator!=(Object &)=0;//纯虚函数,参数必须为引用或指针
virtual void Print()=0;//纯虚函数
virtual ~Object(){} //析构函数可为虚函数,构造函数不行
};
class DblNode{
Object* info; //数据域用指针指向数据类对象
DblNode *llink,*rlink; //前驱(左链)、后继(右链)指针
public:
DblNode(); //生成头结点的构造函数
~DblNode();
void Linkinfo(Object* obj);
friend class DblList;
//以DblList为友元类,DblList可直接访问DblNode的私有函数,与结构一样方便,但更安全
};
DblNode::DblNode(){info=NULL;llink=rlink=NULL;}
DblNode::~DblNode(){
cout<<"删除结点类"<<'\t';
delete info; //释放数据域
}
void DblNode::Linkinfo(Object * obj){info=obj;}
//再定义双链表类,选择常用操作
class DblList{
DblNode *head,*current;
public:
DblList();//构造函数,生成头结点(空链表)
~DblList();//析构函数
void MakeEmpty();//清空链表,只余表头结点
void InsertFront(DblNode* p); //可用来向前生成链表,在表头插入一个结点
void InsertRear(DblNode* p); //可用来向后生成链表,在表尾添加一个结点
void InsertOrder(DblNode* p); //按升序生成链表
DblNode* CreatNode();//创建一个结点(孤立结点)
DblNode* DeleteNode(DblNode* p); //删除指定结点
void PrintList();//打印链表的数据域
int Length();//计算链表长度
DblNode *Find(Object & obj);//搜索数据域与定值相同的结点,返回该结点的地址
//其它操作
};
DblList::DblList(){//建立表头结点
head=new DblNode();
head->rlink=head->llink=head;
current=NULL;
}
DblList::~DblList(){
MakeEmpty();//清空链表
cout<<"删除头结点:";
delete head;
}
void DblList::MakeEmpty(){
DblNode *tempP;
while(head->rlink!=head){
tempP=head->rlink;
head->rlink=tempP->rlink;//把头结点后的第一个节点从链中脱离
tempP->rlink->llink=head;//处理左指针
delete tempP; //删除(释放)脱离下来的结点
}
current=NULL; //current指针恢复
}
void DblList::InsertFront(DblNode *p){
p->llink=head;//注意次序
p->rlink=head->rlink;
head->rlink->llink=p;
head->rlink=p;//最后做
}
void DblList::InsertRear(DblNode *p){
p->rlink=head;//注意次序
p->llink=head->llink;
head->llink->rlink=p;
head->llink=p;//最后做
}
void DblList::InsertOrder(DblNode* p){
if(head==head->llink) {
p->llink=head;//注意次序
p->rlink=head->rlink;
head->rlink->llink=p;
head->rlink=p;//最后做
}
else{
current=head->rlink;
while(current!=head){
if(*current->info>*p->info) break; //找第一个比插入结点大的结点
current=current->rlink;
}
p->rlink=current;//注意次序
p->llink=current->llink;
current->llink->rlink=p;
current->llink=p;//最后做
}
}
DblNode* DblList::CreatNode(){//建立新节点
current=new DblNode();
return current;
}
DblNode* DblList::DeleteNode(DblNode* p){
current=head->rlink;
while(current!=head&¤t!=p) current=current->rlink;
if(current==head) current=NULL;
else{//结点摘下
p->llink->rlink=p->rlink;
p->rlink->llink=p->llink;
p->rlink=p->llink=NULL;
}
return current;
}
DblNode* DblList::Find(Object & obj){//对抽象类只能用“引用”
current=head->rlink;
while(current!=head&&*current->info!=obj) current=current->rlink;
if(current==head) current=NULL;
return current;//搜索成功返回该结点地址,不成功返回NULL
}
void DblList::PrintList(){
current=head->rlink;
while(current!=head){
current->info->Print();
current=current->rlink;
}
cout<<endl;
}
DblList::Length(){
int count=0;
current=head->rlink;
while(current!=head){
count++;
current=current->rlink;
}
return count;
}
//ep8_9.cpp
#include "ep8_9.h"
#include<string>
using namespace std;
class StringObject:public Object{
string sptr;
public:
StringObject();
StringObject(string);
~StringObject();
bool StringObject::operator>(Object & obj);//虚函数
bool StringObject::operator!=(Object & obj);//虚函数
void Print();
};
StringObject::StringObject(){sptr="";}
StringObject::StringObject(string s){sptr=s;}
StringObject::~StringObject(){cout<<"删除字符串类"<<endl;}
bool StringObject::operator>(Object & obj){//虚函数
StringObject & temp=(StringObject &)obj;//必须转换
return sptr>temp.sptr;
}
bool StringObject::operator!=(Object & obj){//虚函数
StringObject & temp=(StringObject &)obj;//必须转换
return sptr!=temp.sptr;
}
void StringObject::Print(){cout<<sptr<<'\t';}//虚函数
int main(){
DblNode * P1;
StringObject* p;
DblList list1,list2,list3;
char *a[5]={"dog","cat","bear","sheep","ox"},*sp="cat";
int i;
for(i=0;i<5;i++){
p=new StringObject(a[i]);//建立数据对象
P1=list1.CreatNode();//建立结点
P1->Linkinfo(p);//数据对象连接到结点
list1.InsertFront(P1);//向前生成list1
p=new StringObject(a[i]);
P1=list2.CreatNode();
P1->Linkinfo(p);
list2.InsertRear(P1);//向后生成list2
}
list1.PrintList();
cout<<"list1长度:"<<list1.Length()<<endl;
list2.PrintList();
cout<<"要求删除的字符串\"cat\""<<endl;
p=new StringObject(sp);//为了程序的通用性只能多一次转换
P1=list1.Find(*p);
delete p;
if(P1!=NULL){
cout<<"删除cat:"<<endl;
P1=list1.DeleteNode(P1);
delete P1;
list1.PrintList();
cout<<"list1长度:"<<list1.Length()<<endl;
}
else cout<<"未找到"<<endl;
cout<<"清空list1:"<<endl;
list1.MakeEmpty();//清空list1
list1.PrintList();
for(i=0;i<5;i++){
p=new StringObject(a[i]);
P1=list3.CreatNode();
P1->Linkinfo(p);
list3.InsertOrder(P1);//升序创建list3
}
list3.PrintList();
cout<<"程序结束:"<<endl;
return 0;
}
矩形法(rectangle)积分近似计算公式为:
被积函数用派生类引入,被积函数定义为纯虚函数。
基类(integer)成员数据包括:积分上下限b和a;分区数n;步长step=(b-a)/n,积分值result。定义积分函数integerate()为虚函数,它只显示提示信息。
派生的矩形法类(rectangle)重定义integerate(),采用矩形法作积分运算。
派生的梯形法类(ladder)和辛普生法(simpson)类似。
请编程,用三种方法对下列被积函数
-
- sin(x),下限为0.0和上限为π/2;
- exp(x),下限为0.0和上限为1.0;
- 4.0/(1+x*x),下限为0.0和上限为1.0。
进行定积分计算,并比较积分精度。
解:使用类参数传递被积函数,因类有数据域,也可以同时传递积分上下限,可由读者进行修改。
#include<iostream>
#include<cmath>
using namespace std;
class Base{
protected:
double result,a,b,step;//Intevalue积分值,a积分下限,b积分上限
int n;
public:
virtual double fun(double x)=0;//被积函数声明为纯虚函数
virtual void Integerate(){
cout<<"这里是积分函数"<<endl;
}
Base(double ra=0,double rb=0,int nn=2000){
a=ra;
b=rb;
n=nn;
result=0;
}
void Print(){
cout.precision(15);
cout<<"积分值="<<result<<endl;
}
};
class Rectangle:public Base{
public:
void Integerate(){
int i;
step=(b-a)/n;
for(i=0;i<=n;i++) result+=fun(a+step*i);
result*=step;
}
Rectangle(double ra,double rb,int nn):Base(ra,rb,nn){}
};
class Ladder:public Base{
public:
void Integerate(){
int i;
step=(b-a)/n;
result=fun(a)+fun(b);
for(i=1;i<n;i++) result+=2*fun(a+step*i);
result*=step/2;
}
Ladder(double ra,double rb,int nn):Base(ra,rb,nn){}
};
class Simpson:public Base{
public:
void Integerate(){
int i;
step=(b-a)/n;
result=fun(a)+fun(b);
for(i=1;i<n;i+=2) result+=4*fun(a+step*i);
for(i=2;i<n;i+=2) result+=2*fun(a+step*i);
result*=step/3;
}
Simpson(double ra,double rb,int nn):Base(ra,rb,nn){}
};
class sinR:public Rectangle{//矩形法和梯形法采用并列结构
public:
sinR(double ra,double rb,int nn):Rectangle(ra,rb,nn){}
double fun(double x){return sin(x);}
};
class sinL:public Ladder{
public:
sinL(double ra,double rb,int nn):Ladder(ra,rb,nn){}
double fun(double x){return sin(x);}
};
class expR:public Rectangle{
public:
expR(double ra,double rb,int nn):Rectangle(ra,rb,nn){}
double fun(double x){return exp(x);}
};
class expL:public Ladder{
public:
expL(double ra,double rb,int nn):Ladder(ra,rb,nn){}
double fun(double x){return exp(x);}
};
class otherR:public Rectangle{
public:
otherR(double ra,double rb,int nn):Rectangle(ra,rb,nn){}
double fun(double x){return (4.0/(1+x*x));}
};
class otherL:public Ladder{
public:
otherL(double ra,double rb,int nn):Ladder(ra,rb,nn){}
double fun(double x){return (4.0/(1+x*x));}
};
class sinS:public Simpson{//辛普生法采用层次结构
public:
sinS(double ra,double rb,int nn):Simpson(ra,rb,nn){}
double fun(double x){return sin(x);}
};
class expS:public sinS{
public:
expS(double ra,double rb,int nn):sinS(ra,rb,nn){}
double fun(double x){return exp(x);}
};
class otherS:public expS{
public:
otherS(double ra,double rb,int nn):expS(ra,rb,nn){}
double fun(double x){return (4.0/(1+x*x));}
};
int main(){
Base *bp;
sinR sr(0.0,3.1415926535/2.0,100);
bp=&sr;
bp->Integerate();//动态,可以访问派生类定义的被积函数
bp->Print();
sinL sl(0.0,3.1415926535/2.0,100);
bp=&sl;
bp->Integerate();//动态,可以访问派生类定义的被积函数
bp->Print();
sinS ss(0.0,3.1415926535/2.0,100);
bp=&ss;
bp->Integerate();//动态,在层次中选
bp->Print();
expR er(0.0,1.0,100);
bp=&er;
bp->Integerate();//动态,可以访问派生类定义的被积函数
bp->Print();
expL el(0.0,1.0,100);
bp=⪙
bp->Integerate();//动态,可以访问派生类定义的被积函数
bp->Print();
expS es(0.0,1.0,100);
bp=&es;
bp->Integerate();//动态,在层次中选
bp->Print();
otherR or(0.0,1.0,100);
bp=∨
bp->Integerate();//动态,可以访问派生类定义的被积函数
bp->Print();
otherL ol(0.0,1.0,100);//增加到100000也达不到辛普生法的精度
bp=&ol;
bp->Integerate();//动态,可以访问派生类定义的被积函数
bp->Print();
otherS os(0.0,1.0,100);
bp=&os;
bp->Integerate();//动态,在层次中选
bp->Print();
return 0;
}