全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:2532
推到 Plurk!
推到 Facebook!

請教TStringList與TList的使用時機?又*,&的正確用法為何

答題得分者是:axsoft
danielj
初階會員


發表:65
回覆:135
積分:40
註冊:2003-06-11

發送簡訊給我
#1 引用回覆 回覆 發表時間:2003-07-25 09:01:48 IP:61.220.xxx.xxx 未訂閱
小弟最近想用TList來存一個資料結構的陣列pointer,但是有問題,我在想或許用TStringList會不會就沒有問題了呢(應該要貼上來請大家過目的,但是沒有存檔就當機了…)? 到底TStringList與TList的用途與用法有何異同呢? 另外,我在存取structure的pointer的時候時常搞不清楚什麼時候要用*p,什麼時候要用&p,能否請版上大大們給小弟一些指引,謝謝啦!
axsoft
版主


發表:681
回覆:1056
積分:969
註冊:2002-03-13

發送簡訊給我
#2 引用回覆 回覆 發表時間:2003-07-25 09:43:48 IP:61.218.xxx.xxx 未訂閱
參考這篇文章試試         

TList vs. TStringList

http://www.bytamin-c.com/articles/Tlvist.htm Using the right list for the right job is a redundant concern in Builder, so I won't waste any disk space talking about it. What I would like to share is the powerful list-maintenance facility both TList and TStringList provide. As you create bigger and better classes in your programming endeavors, you will find that they will naturally want to be maintained in some sort of organized, functional manner. Since I like unrealistic examples, let's pretend you are programming the world. So you wrote a class called TWorld, and now you need to fill your world with stuff. It is very likely that the data members of TWorld will be many many lists. I'll assume the class declaration looks something like:
class TWorld{
              public:TWorld::TWorld();
              TWorld::~TWorld();
              TStringList* Plants;
              TStringList* Animals;
              TList* Oceans;
              TList* Islands;
            };
Yes, I know there's more than that in a typical world, but that's up to you. First you will need to instantiate your lists in your TWorld constructor, something like:
    TWorld::TWorld()
{
 Plants = new TStringList;
 Animals = new TStringList;
 Oceans = new TList;
 Islands = new TList;
} ;
 
OK, so why did I use a TStringList for plants and animals, and TList for oceans and islands? Well, as you should already know, a TStringList maintains a string plus a pointer to an object for each record in it's list, as opposed to just a pointer to an object only. So when I want to use an object in the plants list, I can use it's string variable to denote which type of class the associated object points to. For example, it is assumed that you will have many types of plants in your world, and not just trees. You may have a TFlower class, and a TTree class, among others. Therefore when you add a flower to the Plants list, you should do it like this:
TFlower* Flower = new TFlower;
Plants->Add("Flower", (TObject*) Flower);
     And add trees like this:    TTree* Tree = new TTree;
Plants->Add("Tree", (TObject*) Tree);
 
So long as you cast your class as a TObject* you can add anything you like to a TStringList. When you need access to a plant object you simply recast as such:
TFlower* Flower = NULL;
TTree* Tree = NULL;
for(int i=0 i < Plants->Count; i  ){
  if(Plants->Strings == "Flower"){                    Flower = (TFlower*) Plants->Objects[i];
                ...do something with a flower...
  }      else if(Plants->Strings[i] == "Tree"){
                Tree = (TTree*) Plants->Objects[i];
                ....do something with a tree...
   }
}
 
Of course, this can get a bit sloppy, so the preferred alternative is to use integers to identify which type of class is stored. You do this by setting up a header file with #define statements....
#ifndef mydefsH
#define mydefsH         //PLANT TYPES    #define ptFLOWER 0
#define ptTREE 1
(etc)         //ANIMAL TYPES    #define atBEAR 0
#define atFOX 1
(etc)
#endif    Now when you add something to the plants list, you do it like this:    TFlower* Flower = new TFlower;
Plants->Add(ptFLOWER, (TObject*) Flower);
     And when you need something from the plants list, you can do it like this:    int iType;
for(int i=0; i < Plants->Count; i  ){
        iType = Plants->Strings[i].ToInt();
        switch(iType){
        case ptFLOWER: CallFlowerFunc((TFlower*) Plants->Objects[i]; break;
        case ptTREE: CallTreeFunc((TTree*) Plants->Objects[i]; break;
        }
}
 
So then why do I need a TList* ? Well, for starters, why allocate a bunch of memory to a list of strings if you're not going to use them? TList is nice when you're maintaining a list of objects that are of the same class. Since, for the sake of my example, an ocean is an ocean, and will never be anything else, we could add oceans like this:
TOcean* Ocean = new TOcean();
Oceans->Add(Ocean);
 
Notice I don't have to cast my class as a TObject* when using a TList. A tiny bonus I suppose. Also, when I want to do something with my Oceans, it's simply just a matter of iteration:
    TOcean* O = NULL;
for(int i=0; i < Oceans->Count i  ){O = (TOcean*) Oceans->Items[i];
O->DoSomething();
}
 
Notice the the object list is now referred to as "Items". To me the biggest benefit of TList is the "Remove()" method. If you have a pointer to the object you want to take out of the oceans list, you very simply call the remove method with the pointer to the object:
Oceans->Remove(O);
delete O;
 
This will release all memory associated with the object reference in the list, and adjust the lists Capacity and Count values. To do the same with a TStringList, you must use the "Delete()" method, which means that you'll have obtain an integer index for the objects position in the list, by doing something like:
int ndx = Plants->IndexOfObject((TObject*) Tree);
if(ndx != -1){
         Plants->Delete(ndx);
        Plants->Capacity = Plants->Count;
        delete Tree;
 }
 
Notice that the Capacity had to be manually adjusted afterward, another disadvantage of TStringList vs. TList. If you're now getting ready to argue that in most cases you'd be trying to remove something from a list using an integer index as opposed to a pointer to the object, remember that TList also has the Delete() method, same as the TStringList, but TStringList does not have a Remove() method like the TList. You can maintain a TList of various Plant classes by having your TFlower class and TTree class inherit all the TPlant class data members, and thereby maintaining a PlantType integer as part of the TPlant Class, therefore coding your queries like this:
TPlant* P = NULL;
TFlower* F = NULL;
TTree* T = NULL;
for(int i=0; i < Plants->Count; i  ){
   P = (TPlant*) Plants->Items[i];
    switch(P->PlantType){
    case ptFLOWER: CallFlowerFunc((TFlower*) P); break;
    case ptTREE: CallTreeFunc((TTree*) P); break;
    }
}
 
Of course if you were going to employ this method, I would set up global variables, one for each type of plant, to avoid having to declare a bunch of pointers at the start of each function "just in case" they get used. When destroying a TList or TStringList, you must use the delete operator in combination with a casting call if you want the appropriate destructor for that class to be called as well:
for(int i=0; i < Oceans->Count; i  ) {
        delete (TOcean*) Oceans->Items[i];
}    Oceans->Clear();
delete Oceans;
 
Because TOcean might have it's own list of dynamically allocated objects as one of its data members (ie a TList or TStringlist of fish ) it will need to clear these lists and release any memory associated with them, which we would have also had to code in it's destructor method, therefore we must cast as TOcean when deleting, otherwise it will be deleted as though it were a pointer to type void*. If this confuses you then just always use a pointer to an associated class object as shown below:
TOcean* O = NULL; 
for(int i=0; i < Oceans->Count; i  ) {              O = (TOcean*) Oceans->Items[i];
        delete O;     } 
O = NULL; 
Oceans->Clear();
delete Oceans; 
 
Well, that's it! Hope I didn't bore you too much, and now think about what wonderful list maintenance functions you can write in your apps be it a phone book or a video game. Snakebyte snakebyte@bytamin-c.com www.logsim.co.uk [i]HAVE A NICE DAY FOR YOU
發表人 - axsoft 於 2003/07/25 09:53:07
danielj
初階會員


發表:65
回覆:135
積分:40
註冊:2003-06-11

發送簡訊給我
#3 引用回覆 回覆 發表時間:2003-07-25 10:24:55 IP:61.220.xxx.xxx 未訂閱
謝謝axsoft 版主的回覆,小弟可能要花一些時間消化一下,屆時再針對看不懂的地方請教您,也希望您到時候再幫我解釋一下,謝啦!
系統時間:2024-11-23 7:34:05
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!