【问题标题】:Are there metaclasses or class reference in D?D 中是否有元类或类引用?
【发布时间】:2013-02-24 12:00:29
【问题描述】:

D 中是否有任何类引用系统?为了更准确,我寻找相当于 Delphi 的方法

TMyClassRef = class of TMyClass;

这将用于工厂(就像在 Object 中一样,但不使用类名):

// ideally
void AddNew(*TBaseClass APtr, /*?class_ref_type?*/ AClassType)
{
    *APtr = new AClassType;
}

目前我这样做:

void AddNew(*TBaseClass APtr)
{
    *APtr = new typeof(*APtr);
}

但问题是typeof() 总是返回TBaseClass,而不是TBaseClass 的子类(当子类作为参数传递时)。这显然是在 Delphi 中使用类引用但 D 语言似乎没有这样的系统的情况。

【问题讨论】:

标签: d metaclass class-reference


【解决方案1】:

也许我完全错过了 Delphi 中的想法,但这似乎是模板的用途:

import std.stdio;

class Parent {
    string inherited() {
        return "Hello from parent";
    }

    override string toString() {
        return "Hello from parent";
    }
}

class Child : Parent {
    override string toString() {
        return "Hello from child";
    }
}

void add(C, P)(P* ptr) {
    *ptr = new C;
}

void main() {
    Parent t;
    writeln(t); // prints null

    add!Child(&t);
    writeln(t); // prints Hello from child
    writeln(t.inherited()); // prints Hello from parent
}

这样你传入你想要实例化的类型,而不是那个类型的实例化对象。如果 C 不是 add() 中 P 的子代,这应该会产生编译错误。

编辑:

如果您想更具体地使用 add,您可以这样做:

void add(T : Parent)(Parent* ptr) {
    *ptr = new T;
}

为了让事情变得更好,使用out 参数更惯用:

void add(T : Parent)(out Parent ptr) {
    ptr = new T;
}
void main() {
    Parent p;
    add!Child(p);
}

【讨论】:

  • 谢谢这完美地完成了这项工作。现在可以按照我的意愿传递类型,工厂创建正确的子类型。
【解决方案2】:

就我对 Delphi 概念的理解而言,D 没有以 Delphi 方式引用的类。如果您需要对对象构造做出运行时决策,object.TypeInfo 可能会为您提供帮助。

您可以通过typeid 构造为变量检索TypeInfo

import std.stdio;

class Base
{
    void f()
    {
        writeln("Base");
    }
}

class Descendant : Base
{
    override void f()
    {
        writeln("Descendant");
    }   
}

Base makeNew(Base other)
{
    // cast is needed because create() returns plain Object
    // we can be sure it is Base at least, though, because it was crated from Base
    return cast(Base)typeid(other).create();
}

void main()
{
    Descendant source = new Descendant;
    Base target = makeNew(source);
    // prints "Descendant"
    target.f();
}

此代码示例是否与您想要的相似?

D 通常在运行时操作和编译时操作之间有非常明显的区别。 typeof 在编译时工作,因此在层次结构的情况下无法查询“真实”类类型。

【讨论】:

  • 您的代码示例是相似的,但在我的情况下它不能像这样工作,因为我还没有有效的源...所以 ̉typid(other) 触发 AV。这正是类引用的帮助...有没有其他方法可以查询类型 id,所以在运行时,从一个未初始化的 Object ?
  • 但是如果对象未初始化,则它的运行时类型是未知的(即它可以是基类或其后代之一。)如果您还不想初始化对象,您可以在另一个变量中携带“目标信息”。如果你不清楚,我会发布一些代码。
  • 当然,如果您需要的所有信息在编译时都可用,您可以使用模板。
  • 一般来说,@yaz 刚才所说的。 Delphi 似乎以某种奇怪的方式将编译时世界和符文时相互连接起来。如果您将描述您的用例,我相信可以找到更好的解决方案。 D 在这里非常简单 - 要使用运行时 TypeInfo 你需要现有的对象。如果可以在不实际创建对象的情况下做出决定,则应该通过模板来完成。
猜你喜欢
  • 2011-07-18
  • 1970-01-01
  • 2021-03-16
  • 2021-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-25
  • 2013-07-01
相关资源
最近更新 更多