在C语言中,指针(特别是指向函数的指针)是一个让初学者非常头痛的概念,但是这也是C语言最灵活的特性,如果把指针用好了的话,就可以方便的解决很多复杂的问题,下面我就谈谈我的一点体会,
我最近在开发一个试题库的管理软件,在写其中的《题库信息》这个模块的时侯,其中的分类统计有两种方式:按某种属性的总分值统计和按它所有试题的数量统计,那么就有两个不同的统计函数SumByScore和SumByCount,这样在程序中凡是要统计的地方就得判断要用哪个函数:
if(按分数统计) ......SumByScore(......)......; else ......SumByCount(......)......;
若一处两处还不要紧,但多了就很麻烦了,比如说在我的程序中就要对5种不同的情况进行统计,就显得很不爽了,那么有没有简单一点的办法呢?后来我就用指向函数的指针解决了这个问题,我的思路是这样的:
因为我的两个函数的参数类型都是相同的,也就是数据库的Filter,用的是AnsiString类型,并且返回类型都是int,那么我就定义一个指向函数的指针int (*SumData)(AnsiString);然后在需要进行统计之前根据选择让这个指针指向相应的函数,在以后统计时就用(*SumData)(参数)就可以了,即:
int (*SumData)(AnsiString); SumData=(按分数统计)?SumByScore:SumByCount; ......(*SumData)(参数)......;
可能有人要问,如果参数不同或返回类型不同怎么办?如果返回类型不同,我想也用不着用这样做了;如果是参数不同,可以通过一个中间转换来完成,例如:
int x1(int,char*); int y2(char*,int); //--------------- inline int x1cvr(int m,char* n,char* j,int k) { return x1(m,n); } //---------------- inline int x2cvr(int m,char* n,char* j,int k) { return x2(j,k); } //------------------ main() { int (*x)(int,char*,char*,int); x=(条件)?x1:x2; x(1,"1234","123",2); }
不知家发现了什么?是不是一种方法多种实现?看来用指向函数的指针也可以实现多态性。
附:我的程序中的相关代码(C++Builder 4.0)
//根据指定的FILTER对题库进行分值统计 int SumTable1(AnsiString filter) { AnsiString oldFilter=fmCount->tabTk->Filter; bool oldFiltered=fmCount->tabTk->Filtered; long sum=0; fmCount->tabTk->Filter=filter; fmCount->tabTk->Filtered=true; //-------------------------------------------- fmCount->tabTk->First(); while(!fmCount->tabTk->Eof) { sum+=fmCount->tabTk->FieldByName("Score")->AsInteger; fmCount->tabTk->Next(); } //-------------------------------------------- fmCount->tabTk->Filter=oldFilter; fmCount->tabTk->Filtered=oldFiltered; return sum; } //--------------------------------------------------------------------------- //根据指定的FILTER对题库进行题量统计 int CountTable1(AnsiString filter) { AnsiString oldFilter=fmCount->tabTk->Filter; bool oldFiltered=fmCount->tabTk->Filtered; long sum=0; fmCount->tabTk->Filter=filter; fmCount->tabTk->Filtered=true; sum=fmCount->tabTk->RecordCount; fmCount->tabTk->Filter=oldFilter; fmCount->tabTk->Filtered=oldFiltered; return sum; } //----------------------------------------------------------------------------- void __fastcall TfmCount::btTeeClick(TObject *Sender) { int SumTable1(AnsiString filter); int CountTable1(AnsiString filter); //清空图表 this->Series1->Clear(); int i; int (*CountType)(AnsiString); //根据统计类型选相应的统计函数 CountType=(rdGrpCountType->ItemIndex==1)?CountTable1:SumTable1; switch (rdGrpItem->ItemIndex) { //按章节统计 case 0: { for(i=1;i<=tabKm->FieldByName("MostChapter")->AsInteger;i++) { AnsiString tmpFilter="Chapter="; tmpFilter+=AnsiString(i); Series1->AddBar((*CountType)(tmpFilter), AnsiString("第")+AnsiString(i)+AnsiString("章"), clTeeColor); } break; } //按题型统计 case 1: { tabTx->First(); while(!tabTx->Eof) { AnsiString tmpFilter="TestNumber="; tmpFilter+=tabTx->FieldByName("TestNumber")->AsString; Series1->AddBar((*CountType)(tmpFilter), tabTx->FieldByName("TestQuestions")->AsString, clTeeColor); tabTx->Next(); } break; } //按难度统计 case 2: { char strNd[5][5]={"容易","偏易","一般","偏难","困难"}; for(i=1;i<=5;i++) { AnsiString tmpFilter="Difficulty="; tmpFilter+=AnsiString(i); Series1->AddBar((*CountType)(tmpFilter), strNd[i-1], clTeeColor); } break; } //按档次统计 case 3: { Series1->AddBar((*CountType)("Level=/'一般/'"), "一般", clTeeColor); Series1->AddBar((*CountType)("Level=/'重点/'"), "重点", clTeeColor); break; } //按三基统计 case 4: { Series1->AddBar((*CountType)("ThreeBasic=/'基本知识/'"), "基本知识", clTeeColor); Series1->AddBar((*CountType)("ThreeBasic=/'基本理论/'"), "基本理论", clTeeColor); Series1->AddBar((*CountType)("ThreeBasic=/'基本技能/'"), "基本技能", clTeeColor); break; } } } //---------------------------------------------------------------------------