1

我使用 C++ 已经有一段时间了,偶尔让我烦恼的一件事是我还没有弄清楚如何在 C++ 中完成这个 Delphi Factory 构造。

我无法弄清楚的关键部分是如何在 C++ 中传递对类类型的引用。在 Delphi 中,我们有“TClass”类型。这种类型的变量是对某个类的引用。我们可以使用class of MyClass语法来限制类引用可以引用的类来定义新的类引用类型。

请注意,术语“Delphi 类引用”=/=“类的 C++ 实例”

对于那些不熟悉 Pascal 的人,变量是声明的,variable: type而不是 C 风格的type variable。同样,函数的返回类型出现参数列表和名称之后。

我在下面的例子中压缩了语法以减少样板,因此向 Delphi 开发人员道歉,因为格式很糟糕。关键部分在评论中描述。

program demo;

{$APPTYPE CONSOLE}

// declarations

type

  Base = class
  public constructor Create(name: string); virtual;
  end;

  // Class reference which refers to Base and its descendants
  BaseClass = class of Base;

  ChildA = class(Base)
  public constructor Create(name: string); override;
  end;

  ChildB = class(Base)
  public constructor Create(name: string); override;
  end;

// implementation

constructor Base.Create(name: string);
begin
  WriteLn('Base says hi to ' + name);
end;

constructor ChildA.Create(name: string);
begin
  inherited Create(name);
  WriteLn('ChildA says hi to ' + name);
end;

constructor ChildB.Create(name: string);
begin
  WriteLn('ChildB says hi to ' + name);
end;

// *** THIS IS THE BIT THAT I'M INTERESTED IN ***
// The function doesn't know at compile time exactly what class it is being
// asked to construct.  The compiler knows that it is or inherits from Base.
// I can't find any kind of "class reference" in C++.
function ConstructSomething(ClassType: BaseClass; name: string): Base;
begin
  Result := ClassType.Create(name);
end;

// Equivalent to "main()" in C
begin

  // Pass references to a class to the ConstructSomething function
  ConstructSomething(Base, 'Mark');
  WriteLn('');

  ConstructSomething(ChildA, 'Mark');
  WriteLn('');

  ConstructSomething(ChildB, 'Mark');
  WriteLn('');

end.

输出:

Base says hi to Mark

Base says hi to Mark
ChildA says hi to Mark

ChildB says hi to Mark

请注意,当传递对子类的引用时,将创建子类。在此演示中,有意不调用 ChildB 中的基本构造函数,以使“类引用”概念更加明显。

4

2 回答 2

5

您可以获得的最接近的是使用模板函数

template<typename ClassType>
Base* ConstructSomething(string name)
{
   return new ClassType(name);
}

int main()
{
    ConstructSomething<Base>("Mark");
    ConstructSomething<ChildA>("Mark");
}

ClassType不能在运行时选择 - 它必须在编译期间知道。

于 2014-08-15T19:39:36.603 回答
1

C++ 没有像 Delphi 那样内置的类引用。类引用不仅仅是虚拟构造函数。您还可以定义(虚拟和非虚拟)类方法,非常方便。

您可以使用 C++ 模板来模仿类引用,但它带有一些样板代码,并且您必须为类和元类定义单独的类。更不用说这是一种相当单一的 C++ 方式。

// some central header

template <typename Base>
  class Metaclass;


// your header

class Base
{
public:
  Base (const String& name) { /*...*/ }
};
template<>
  class Metaclass<Base>
{
public:
  virtual Base* create (const String& name);
};
extern Metaclass<Base> classof_Base;

class ChildA : public Base
{
public:
  ChildA (const String& name) { /*...*/ }
};
template<>
  class Metaclass<ChildA> : public Metaclass<Base>
{
public:
  // note how I'm making use of C++'s support for covariance
  ChildA* create (const String& name) override;
};
extern Metaclass<ChildA> classof_ChildA;

class ChildB : public MyBase
{
public:
  ChildB (const String& name) { /*...*/ }
};
template<>
  class Metaclass<ChildB> : public Metaclass<Base>
{
public:
  ChildB* create (const String& name) override;
};
extern Metaclass<ChildB> classof_ChildB;


// your source file

Metaclass<Base> classof_Base;
Base* Metaclass<Base>::create (const String& name)
{
  return new Base (name);
}

Metaclass<ChildA> classof_ChildA;
MyBase* Metaclass<ChildA>::create (const String& name)
{
  return new ChildA (name);
}

Metaclass<ChildB> classof_ChildB;
MyBase* Metaclass<ChildB>::create (const String& name)
{
  return new ChildB (name);
}

现在您可以在 C++ 中复制您的 Delphi 代码:

Base* constructSomething (Metaclass<Base>& classType, const String& name)
{
  return classType.create (name);
}

int main (void)
{
  constructSomething (classof_Base, "Mark");
  std::sprintf ("\n");
  constructSomething (classof_ChildA, "Mark");
  std::sprintf ("\n");
  constructSomething (classof_ChildB, "Mark");
  std::sprintf ("\n");
}
于 2014-08-15T20:38:21.193 回答