关于虚函数和接口 |
尚未結案
|
ilikeff8
一般會員 發表:12 回覆:16 積分:5 註冊:2002-12-28 發送簡訊給我 |
我一作业用bcb class IOp // Father Class Uses Sub Class's function and Sub Class fill the function info.
{
public:
virtual void ReadRecord(void){};
virtual void WriteRecord(void){};
virtual SFIELD& FieldByIndex(int){ return NULLFIELD; };
virtual int GetFieldTotalNumber(void){ return 0; };
};
//---------------------------------------------------------------------------
class TRecordActive:public IOp
{
private:
AnsiString FConfigFileName,FSection,FDataFileIdent,DataFile,SearchFieldName,
FSearchValue,FSearchValue2,FStringGridName,FSearchComboBoxName;
TStringList *RecordNO;
void FillRecord(bool);
void AddColumn(SFIELD);
void FillToStringGrid(void);
void GetRecordFromComponents(void);
void GetFromStringGrid(int);
void PutRecordToComponents(void);
void FillSearchComboBoxByFields(void);
bool CheckBySearch(SFIELD,AnsiString);
bool CheckBySearch(SFIELD,AnsiString,AnsiString);
void SetSearchFieldName(AnsiString Value);
protected:
TForm *FForm;
int FHandle;
TStringGrid *FStringGrid;
void InitStringGrid(void);
public:
::TRecordActive(void)
{
FConfigFileName="";
DataFile="";
FHandle=-1;
SearchFieldName="";
FStringGridName="";
FSearchComboBoxName="";
RecordNO=new TStringList();
}
~TRecordActive(void)
{
delete RecordNO;
}
__property TForm *Form={read=FForm,write=FForm};
__property AnsiString ConfigFileName={read=FConfigFileName,write=FConfigFileName};
__property AnsiString Section={read=FSection,write=FSection};
__property AnsiString DataFileIdent={read=FDataFileIdent,write=FDataFileIdent};
__property AnsiString StringGridName={read=FStringGridName,write=FStringGridName};
__property AnsiString SearchComboBoxName={read=FSearchComboBoxName,write=FSearchComboBoxName};
bool Init(AnsiString,AnsiString);
void InitComponent(void);
bool LoadFromFile(bool);
void SaveToFile(void);
bool Add(void);
void ShowValue(void);
bool Modify(void);
bool Delete(void);
void SetSearchComponentsVisible(AnsiString,AnsiString,AnsiString,AnsiString);
SFIELD& FieldByName(AnsiString);
SFIELD& FieldByCName(AnsiString);
void Search(AnsiString,AnsiString);
};
//---------------------------------------------------------------------------
写到后来发现其实在IOP的函数完全可以在TRecordActive中定义,甚至可以不用定义成虚函数,只是普通函数让后代有必要的话重载就可以了,虚函数在这里没有起到太大的作用,只是结构清晰点而已,也似乎在这种情况下才有点用: class IA
{
...
virtual void DOSOMETING(){};
}
TForm1:public TForm,IA
{
...
void DOSOMETING()
{
do someting;
}
}
.....
void F(IA *A)
{
IA->DOSOMETING();
}
TForm::Show(...)
{
TA a=new TA();
F(this);
} 但不太实用,虽越来越喜欢用虚的,但不得精髓,容易画蛇添足
,在什么情况下用虚函数,而什么情况下用重载好呢?,或者说也看到了虚函数的好处和未来升格成一个COM系统开发员的前景,但还是意识模糊
|
ilikeff8
一般會員 發表:12 回覆:16 積分:5 註冊:2002-12-28 發送簡訊給我 |
|
brant
一般會員 發表:1 回覆:64 積分:23 註冊:2003-04-07 發送簡訊給我 |
寫一個簡單的例子給你:
#include <iostream> using namespace std; class A { public: //void AA(){cout<<"I am A"<把class A對AA()的宣告互換試一下 你應該就能知道什麼時候要用 virtual function 了。 (記得把大小於箭頭改成半型的) 發表人 - brant 於 2003/06/11 10:41:10 |
ilikeff8
一般會員 發表:12 回覆:16 積分:5 註冊:2002-12-28 發送簡訊給我 |
引言: 寫一個簡單的例子給你:你这个例子很好,理顺里一下头绪,虽然一直在用虚函数的功能,但一直把它与重载的功能原理搞混了 class A { public: /*virtual*/ void AA(void){ ShowMessage("A") ; } }; class B:public A { public: void AA(void); }; class C:public A { public: void AA(void); }; void B::AA(void) { ShowMessage("B"); }; void C::AA(void) { ShowMessage("C"); }; void test(A *a) { a->AA(); }; ... void __fastcall TForm1::Button1Click(TObject *Sender) { B b; C c; test(&b); test(&c); } 如果没有加virtual, test(&b); test(&c); 都只会调用父类的AA 只有加上virtual 才能调用它们自己的AA 是否可以这样理解: 重载只是让后代能使用父类的功能,遇上同名将忽略后代同名方法 而虚函数可能让后代改写父类的功能,遇上同名将忽略父代同名方法,但可以Inherited 理了下思路,往往东西做出来了事后却忘了自己是怎么做的,真倒#include <iostream> using namespace std; class A { public: //void AA(){cout<<"I am A"<把class A對AA()的宣告互換試一下 你應該就能知道什麼時候要用 virtual function 了。 (記得把大小於箭頭改成半型的) 發表人 - brant 於 2003/06/11 10:41:10 |
brant
一般會員 發表:1 回覆:64 積分:23 註冊:2003-04-07 發送簡訊給我 |
|
ilikeff8
一般會員 發表:12 回覆:16 積分:5 註冊:2002-12-28 發送簡訊給我 |
推而广之,我想应该可以用在这种场合:
版权:试用版,对某功能进行限制
//---------------------------------------------------------------------------
//#define DemoVersion
class TA
{
public:
#ifndef DemoVersion
virtual
#endif
void DOSOMETING(void);
};
//---------------------------------------------------------------------------
class TB:public TA
{
public:
void DOSOMETING(void);
};
//---------------------------------------------------------------------------
void TA::DOSOMETING(void)
{
ShowMessage("This Version can't use this function.");
}
//---------------------------------------------------------------------------
void TB::DOSOMETING(void)
{
ShowMessage("!");
}
//---------------------------------------------------------------------------
void DoFunction(TA *A)
{
A->DOSOMETING();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
TB *B=new TB();
DoFunction(B);
}
//---------------------------------------------------------------------------
|
brant
一般會員 發表:1 回覆:64 積分:23 註冊:2003-04-07 發送簡訊給我 |
是可以這樣用沒錯啦
但這不是C++所定義這個關鍵字及語法的原義
重點在polymorphism 我之前已經講了
virtual跟polymorphism是一體兩面
polymorphism就是以父類的介面
事實上去調用子類的操作
這在一個父類有很多種子類
都有一種共同的操作時
只要把子類轉型成父類去呼叫該操作
就會調用到子類的操作而不會去調用到父類的操作
進而就可以用同一個函數當入口
將參數宣告成父類(就像我舉例的test(A* a))
然後在裡面用父類的介面直接呼叫
不用再去判斷以父類傳進來的類別是哪個子類
再去轉成子類,再去調到需要的成員函數
或是將子類轉型成父類去調用該操作
而不用管這個子類到底是哪種子類 這樣寫出來的程式碼會比較好懂比較優雅 譬如說定義一種父類叫 airplane
有一個操作叫 fly
然後可以有 plane747、planeF16、planeIDF、smallplane四種類去繼承airplane
這四種飛機的飛法都不一樣
然後我們用某種法式產生了這四種飛機各若干架
都在天空飛,方向、速度都不同
但這些飛機都放在一個 airplane * 的 link list裡面
有一個timer,每一秒更新這些飛機的位置
就需要把這個list從頭到尾跑一遍
一一呼叫它們的fly
如果airplane的fly不是virtual,那一叫它們的fly就只會照原本airplane定義的飛法在飛
如果要分別判斷目前的airplane是哪種子類,再轉型去呼叫正確的fly
程式碼又臭又長,效率又不好
所以就需要把airplane的fly宣告為virtual
這樣就可以在尋訪這個list的時候
把各種飛機都當作是飛機,只要叫它飛
它自己會照它自己的方式去飛
我們不需要知道它是哪種飛機
程式碼寫起來只是短短幾行
也少了很多型別的判斷,效率也比較好 如果您還是想不通我所說的
建議您在polymorphism這方面下點工夫 發表人 -
|
ilikeff8
一般會員 發表:12 回覆:16 積分:5 註冊:2002-12-28 發送簡訊給我 |
引言: 是可以這樣用沒錯啦 但這不是C 所定義這個關鍵字及語法的原義 重點在polymorphism 我之前已經講了 virtual跟polymorphism是一體兩面 polymorphism就是以父類的介面 事實上去調用子類的操作 這在一個父類有很多種子類 都有一種共同的操作時 只要把子類轉型成父類去呼叫該操作 就會調用到子類的操作而不會去調用到父類的操作 進而就可以用同一個函數當入口 將參數宣告成父類(就像我舉例的test(A* a)) 然後在裡面用父類的介面直接呼叫 不用再去判斷以父類傳進來的類別是哪個子類 再去轉成子類,再去調到需要的成員函數 或是將子類轉型成父類去調用該操作 而不用管這個子類到底是哪種子類 這樣寫出來的程式碼會比較好懂比較優雅 譬如說定義一種父類叫 airplane 有一個操作叫 fly 然後可以有 plane747、planeF16、planeIDF、smallplane四種類去繼承airplane 這四種飛機的飛法都不一樣 然後我們用某種法式產生了這四種飛機各若干架 都在天空飛,方向、速度都不同 但這些飛機都放在一個 airplane * 的 link list裡面 有一個timer,每一秒更新這些飛機的位置 就需要把這個list從頭到尾跑一遍 一一呼叫它們的fly 如果airplane的fly不是virtual,那一叫它們的fly就只會照原本airplane定義的飛法在飛 如果要分別判斷目前的airplane是哪種子類,再轉型去呼叫正確的fly 程式碼又臭又長,效率又不好 所以就需要把airplane的fly宣告為virtual 這樣就可以在尋訪這個list的時候 把各種飛機都當作是飛機,只要叫它飛 它自己會照它自己的方式去飛 我們不需要知道它是哪種飛機 程式碼寫起來只是短短幾行 也少了很多型別的判斷,效率也比較好 而且用多型,往後的擴充性比較好: 以後如果發明了一種飛機叫 tirtleplane 也只要繼承 airplane,設計出飛得很龜的 fly 然後同樣丟到那個 list 裡面去 其他地方的程式碼都不用改 天空中就可以多一種很龜的飛機在飛來飛去 於是天空中就有飛得很龜的 也有飛得很快的飛機了 如果您還是想不通我所說的 建議您在polymorphism這方面下點工夫 發表人 - >>< face="Verdana, Arial, Helvetica"> 你讲的是没错拉,而我讲的是比较另类的一种“用法”而已 |
brant
一般會員 發表:1 回覆:64 積分:23 註冊:2003-04-07 發送簡訊給我 |
|
ilikeff8
一般會員 發表:12 回覆:16 積分:5 註冊:2002-12-28 發送簡訊給我 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |