2010-12-20 18 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など)は書き込まれません。これは、上記のような 'ヌル'ミックスインでさえあります。

私のコードは、TForm、TEditなどからクラスを直接派生させただけでうまく動作し、クラスはストリーミングシステムに正しく登録されています。

答えて

8

速い/簡単な答えは次のとおりです。テンプレートを扱う場合、コンパイラはストリーミングを動作させるための適切な記述子を生成しません。しかし、これは前に出てきたので、私は何が欠けているかを見つけるためにカバーの下を覗いた。私が見つけたのは、それがほぼそこにあるということです。だからもう少し詳しい情報があります。

アップフロントでは、テンプレートベースの型は決してデルファイとして扱われません。例えば、このような何か:

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

を...そして、あなたは、エラーが表示されます

エラー E2242 TEST.CPP 53:__classid(すなわちクラスが__declspecマークのDelphiスタイルのクラス型が必要です(delphiclass)またはSystem :: TObjectから派生した)関数のテスト() "

これは基本的にコンパイラはこの型/クラスをDelphiクラス[ie TObjectから派生したもの]。内部的には、型がデルファイと互換性があるかどうかを示すシンボルのフラグがあります。そして、私はそれがオブジェクトのインスタンスを作成する場合、それが何かする必要がある階層を歩くことを余儀なくされた場合、デルファイスタイルとして型をマーキングするためにコンパイラを騙すことができることに気づいた。だから、これはエラーをハックして消える:

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クラスは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、ミックスインをその基本型が3 :(

私はストリーミングsysteを疑うがありながら、 '0' パブリッシュプロパティに現れますmはこのカウントに依存しているため、継承されたプロパティはセットアップで書き出されません。

実行時に生成された記述子を調整することを検討しましたが、_TEXTに書き込むので、DEPをトリガーするようにバインドされています。

PropCountを計算して、正しい数を計算する方法があるかどうかを調べるロジックを見ていきます。時間が許せば、これのためのQCを開けてください:私はそれが期待どおりに動作するように多くの努力を必要としないと信じています。

乾杯、

ブリュノー

PS:私のサンプルでは、​​私もミックスインのプロパティを公開していたし、コンパイラはそのプロパティの正しい記述子を生成し;しかし、総数はまだゼロだった。

+0

ありがとうブルネイ - 素晴らしい答えです、そして、本当にここにお会いできてうれしいです! – Roddy

+0

ログインしていますQC:http://qc.embarcadero.com/wc/qcmain.aspx?d=90446 – Roddy

+0

また、私はE2242の問題と同様の問題をしばらく前に見つけました。http:// qcとして報告されました.embarcadero.com/wc/qcmain.aspx?d = 67683 – Roddy