代码如下  sTableNames := TStrings.Create;
  Screen.Cursor:=crHourGlass;
  SetDbPath.SetConnection(ADOC);
  ADOQ.Connection := ADOC;
  ADOC.GetTableNames(sTableNames,False);  //这里产生了一个Abstract Error  抽象类型错误?
  for i := 0 to  sTableNames.Count -1  do
  Begin
    ADOQ.SQL.Text := 'Drop Table ' + sTableNames[i];
    ADOQ.ExecSQL;
  end;明明GetTableNames的原型是
GetTableNames(List: TStrings;SystemTables: Boolean);为什么我用TStrings做参数却不行呢??非得要用TStringList做参数吗?虽然TStringList是它的一个子类,
难道TStrings是抽象类(好象类都是抽象的)问题是如果把Table给TlistBox的Item又不会报错,Item可是一个TStrings对象啊 

解决方案 »

  1.   

    你的做法与我原来的一模一样,我也是立即改用TStringList来解决问题,只是我当时没深究其中原委。仔细想来应该是抽象类的事,TlistBox的Item是一个TStrings对象,但你使用时它已经为一个实例。如果我们去追踪TlistBox之Item的实现过程,也许它也是一个TStringList!
      

  2.   

    TStrings的确是一个抽象类,它存在以下方法:
    function Get(Index: Integer): string; virtual; abstract;
    function GetCount: Integer; virtual; abstract;
    procedure Clear; virtual; abstract;
    procedure Delete(Index: Integer); virtual; abstract;
    procedure Insert(Index: Integer; const S: string); virtual; abstract;
    而你的GetTableNames(List: TStrings;SystemTables: Boolean);函数实现是这样的。procedure TADOConnection.GetTableNames(List: TStrings;
      SystemTables: Boolean);
    var
      TypeField,
      NameField: TField;
      TableType: string;
      DataSet: TADODataSet;
    begin
      CheckActive;
      DataSet := TADODataSet.Create(nil);
      try
        OpenSchema(siTables, EmptyParam, EmptyParam, DataSet);
        TypeField := DataSet.FieldByName('TABLE_TYPE'); { do not localize }
        NameField := DataSet.FieldByName('TABLE_NAME'); { do not localize }
        List.BeginUpdate;
        try
          List.Clear;
          while not DataSet.EOF do
          begin
            TableType := TypeField.AsString;
            if (TableType = 'TABLE') or (TableType = 'VIEW') or     { do not localize }
               (SystemTables and (TableType = 'SYSTEM TABLE')) then { do not localize }
              List.Add(NameField.AsString);
            DataSet.Next;
          end;
        finally
          List.EndUpdate;
        end;
      finally
        DataSet.Free;
      end;
    end;//这里面使用了抽象方法,而你实例化的是一个TStrings的抽象类,它本身并没有实现List.Clear;之类的方法,当然会出错
      

  3.   

    尽管Delphi允许我们创建一个抽象类的对象实例,但我们只能访问这个抽象类中已经实现了的方法,而不能访问其抽象方法,GetTableNames函数对抽象方法Clear的调用就出错了,抽象类可以实例化但最好不要去实例化它,在C++和JAVA中都不支持其实例化。
    其中
    GetTableNames(List: TStrings;SystemTables: Boolean);
    它的List: TStrings 参数的约定并不是一定要用TStrings类型的对象去做参数,而是指从TStrings派伸出来的实现了抽象方法的其他类对象都可以做为参数。
    List更多的是做为引用这些对象的意思。因为一个祖先类的变量可以引用它的子类的对象。
      

  4.   

    TStringList 为什么可以呢,是因为TStringList实现了与GetTableNames相关的抽象方法,所以没有问题。
      

  5.   

    tstrings是虚类,tstringlist是tstrings的一个子类,它不是虚类,实现了tstrings类里的一些虚方法。所以一般用tstringlist。如果你想自己写一个字符串序列之类的类,可以从tstrings派生。
      

  6.   

    no,像items,lines,List等本身就是TStringList,
    这是很简单的道理,在D中,
    如:我说的肯定是比如啊,呵呵,一个函数用TEDIT不会说你用somefun(somevar:TEDIT;……),而用somefun(somevar:Twincontrol;……)
      

  7.   

    楼上:Delphi是允许你创建一个“形状”。
      

  8.   

    Tstrings抽象类的某些方法要子类(Tstringlist)实现,抽象类本身只声明不实现
      

  9.   

    支持 
    hottey(点亮心灵)(基础补习中)  
    qizhanfeng(glacier)
      

  10.   

    早上来上班看得楼上这么多精确的解释,总算明白了一点点,却还有一点不明白,既然TStrings的某些方法是抽象的,需要在子类里面实现的,可是TListbox为什么又可以用TStrings呢  TCustomListBox = class(TCustomMultiSelectListControl)
      private
        FAutoComplete: Boolean;
        FCount: Integer;
        FItems: TStrings;
    .....
        property Items: TStrings read FItems write SetItems;
    .........procedure TCustomListBox.SetItems(Value: TStrings);
    begin
      if Style in [lbVirtual, lbVirtualOwnerDraw] then
        case Style of
          lbVirtual: Style := lbStandard;
          lbVirtualOwnerDraw: Style := lbOwnerDrawFixed;
        end;
      Items.Assign(Value);
    end;
      

  11.   

    楼主看来没仔细看我的回复:
    既然TStrings的某些方法是抽象的,需要在子类里面实现的,Delphi中是允许对抽象类进行实例化的,这一点和C++以及Java是不同的,我们声明一个TString的对象时,还是可以访问其实现了的普通方法的,只要你不访问它的抽象方法,就不会产生
    Abstract Error 错误。毕竟Tstring也定义并实现了一些普通方法,因此FItems: TStrings; 时,即使是用TStrings来构造FItems 也不会出现问题,除非你使用TStrings 的抽象方法时才会出现错误,并且大多数情况下我们这么声明FItems: TStrings;并不是为了去用TStrings去构造FItems,更多的是一种对子类实例对象的引用。以此来使FItems 来表现出不同的行为。