2010-12-20 61 views
3

我正在嘗試使用C++模板'mixins'來創建一些具有共享附加功能的新VCL組件。例如...C++模板與VCL類很好地玩嗎?

template <class T> class Mixin : public T 
{ 
private: 
    typedef T inherited; 

// ...additional methods 

public: 
    Mixin(TComponent *owner) : inherited(owner) 
    { 
    // .. do stuff here 
    }; 
}; 

像這樣來使用:

現在
class MyLabel : public Mixin<TLabel> 
{ 
    .... 
} 

class MyEdit : public Mixin<TEdit> 
{ 
    .... 
} 

,一切編譯罰款,並混入東西似乎工作 - 直到我嘗試使用組件保存到一個流TStream-> WriteComponent,其中繼承的屬性(例如TLabel.Width/Height /等)不被寫入。這甚至與上面顯示的'null'混合。

當我直接從TForm,TEdit等派生類時,我的代碼工作正常,並且該類在流式系統中正確註冊。

回答

8

快速/簡單的答案是:不;當處理模板時,編譯器將不會生成正確的描述符來使流式處理工作。然而,既然這是以前出現的,我在封面下偷看了一下,發現了缺失的東西。我發現它幾乎就在那裏。所以這裏有更多的信息。

編譯器不會將基於模板的類型視爲Delphi。例如,做這樣的事情:

void testing() 
{ 
    __classid(Mixin<Stdctrls::TLabel>); // Error Here 
} 

...你會看到錯誤

錯誤 E2242 TEST.CPP 53:__classid要求德爾福風格類類型標記__declspec(即類(delphiclass)或派生自System :: TObject)在功能測試()「

這基本上說,編譯器不認爲這種類型/類與Delphi類[兼容那些從TObject派生]。在內部,符號上只有一個標誌,表示類型是否與delphi兼容。我注意到,如果我強迫它沿着層次結構走,我可以欺騙編譯器將其類型標記爲delphi風格。如果創建對象的實例,這是必須做的事情。所以,用這種破解錯誤消失:

void testing() 
{ 
    typedef Mixin<Stdctrls::TLabel> __ttype; 
    std::auto_ptr<__ttype> c2(new __ttype(0)); 
    __classid(Mixin<Stdctrls::TLabel>); // No more errors here 
} 

但好得多實際上對模板直接使用__declspec(delphiclass),如:所以現在

template <class T> 
class __declspec(delphiclass) Mixin : public T { 
private: 
    int i; 
    typedef T inherited; 
public: 
    __fastcall Mixin(TComponent *owner) : inherited(owner) {}; 
}; 

,該編譯器將類型是一個沒有黑客的delphi風格的類,我偷看了一下,發現了你可能遇到的問題:Delphi類有TTypeData.PropCount字段 - http://docwiki.embarcadero.com/VCL/en/TypInfo.TTypeData - 這是類的屬性的總和,包括那些的基類。由於信息的各條計算的方式,編譯器寫入一個「0」模板時參與:(

您可以通過打印出PropCount看到這一點,因爲在這一領域:

#include <Stdctrls.hpp> 
#include <cstdio> 
#include <memory> 
#include <utilcls.h> 

class TCppComp : public Classes::TComponent { 
    int i; 
public: 
    __fastcall TCppComp(TComponent* owner): Classes::TComponent(owner) {}; 
__published: 
    __property int AAAA = {read=i, write=i}; 
}; 

template <class T> 
class __declspec(delphiclass) Mixin : public T { 
private: 
    int i; 
    typedef T inherited; 
public: 
    __fastcall Mixin(TComponent *owner) : inherited(owner) {}; 
}; 

typedef Mixin<TCppComp> TMixinComp; 

void showProps(TClass meta) { 
    PTypeInfo pInfo = PTypeInfo(meta->ClassInfo()); 
    int Count = GetPropList(pInfo, tkAny, NULL); 
    TAPtr<PPropInfo> List(new PPropInfo[Count]); 
    std::printf("Class: %s - Total Props:%d\n", 
        AnsiString(pInfo->Name).c_str(), Count); 
    GetPropList(pInfo, tkAny, *(reinterpret_cast<PPropList*>(&List))); 
    for (int i = 0; i < Count; i++) { 
    AnsiString propName(List[i]->Name); 
    std::printf("\t%s\n", propName.c_str()); 
    } 
} 

void test() { 
    showProps(__classid(TCppComp)); 
    showProps(__classid(TMixinComp)); 
} 

int main() { 
    test(); 
    return 0; 
} 

當運行上述打印:

Class: TCppComp - Total Props:3 
    AAAA 
    Name 
    Tag 
    Class: @%Mixin$8TCppComp% - Total Props:0 

IOW,密新示出了 '0' 出版的性質,同時它的基類型具有3 :(

我懷疑流SYSTE m依賴於這個計數,這就是爲什麼繼承的屬性沒有被寫入你的設置。

我認爲在運行時調整了生成的描述符,但是因爲我們將它們寫入_TEXT,所以它必然會觸發DEP。

我會看看計算PropCount的邏輯,看看是否有辦法讓它計算正確的數字。如果時間允許,請爲此打開一個質量控制:現在我已經在下面窺視了,我相信它不需要很多努力就能按預期工作。

乾杯,

布諾

PS:在我的示例我甚至有密新發布的屬性和編譯器生成的該屬性的正確描述;然而,總數仍然是零。

+0

謝謝布魯諾 - 很好的答案,很高興見到你在這裏! – Roddy 2010-12-21 10:42:39

+0

登錄QC:http://qc.embarcadero.com/wc/qcmain.aspx?d=90446 – Roddy 2010-12-21 10:54:14

+0

此外,我偶然發現了一個類似的問題,回到E2242問題:它報告爲http:// qc .embarcadero.com/WC/qcmain.aspx?d = 67683 – Roddy 2010-12-21 11:09:14

相關問題