C++模板可以很好地与VCL类一起使用吗?

Rod*_*ddy 3 delphi templates vcl c++builder

我正在尝试使用C++模板'mixins'来创建一些具有共享附加功能的新VCL组件.例...

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

// ...additional methods

public:
  Mixin(TComponent *owner) : inherited(owner)
  {
  // .. do stuff here
  };
};
Run Code Online (Sandbox Code Playgroud)

像这样使用:

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

class MyEdit : public Mixin<TEdit>
{
  ....
}
Run Code Online (Sandbox Code Playgroud)

现在,一切编译都很好,mixin的东西似乎工作 - 直到我尝试使用TStream-> WriteComponent将组件保存到流中,其中继承的属性(例如TLabel.Width/Height/etc.)不会被写入.即使使用如上所示的'null'mixin也是如此.

直接从TForm,TEdit等派生类时,我的代码工作正常 - 并且该类已正确地注册到流系统.

Bru*_*auB 8

快速/简单的答案是:不; 在处理模板时,编译器不会生成适当的描述符来使流工作.然而,由于之前出现了这个问题,我偷看了封面,找出了遗漏的内容.而我发现它几乎就在那里.所以这里有更多信息.

在前面,编译器永远不会将基于模板的类型视为Delphi.例如,做这样的事情:

void testing()
{
  __classid(Mixin<Stdctrls::TLabel>); // Error Here
}
Run Code Online (Sandbox Code Playgroud)

......你会看到错误

" 错误 E2242 test.cpp 53:__ classd在函数testing()中需要Delphi样式类类型(即类标记__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
}
Run Code Online (Sandbox Code Playgroud)

但更好的是直接在模板上使用__declspec(delphiclass),如:

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

所以现在编译器将类型视为一个没有黑客的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;
}
Run Code Online (Sandbox Code Playgroud)

运行以上打印时:

  Class: TCppComp - Total Props:3
    AAAA
    Name
    Tag
  Class: @%Mixin$8TCppComp% - Total Props:0
Run Code Online (Sandbox Code Playgroud)

IOW,Mixin显示'0'发布的属性,而其基本类型有3 :(

我怀疑流式传输系统依赖于这个计数,这就是为什么继承的属性没有在你的设置中写出来的原因.

我考虑在运行时调整生成的描述符,但是因为我们将它们写入_TEXT,它必然会触发DEP.

我将查看计算PropCount的逻辑,看看是否有某种方法可以让它计算出正确的数字.如果时间允许的话,请为此开一个质量控制:现在我已经偷看了,我相信不需要太多努力就能让它按预期工作.

干杯,

布诺

PS:在我的示例中,我甚至让Mixin发布了一个属性,编译器为该属性生成了正确的描述符; 但是,总数还是零.