Есть метаклассы или ссылки на классы в D?

Есть ли какая-нибудь система ссылки на класс в 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, похоже, не имеет такой системы.

2 ответа

Решение

Может быть, я полностью упускаю идею в 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 не является потомком P в add().

Редактировать:

Если вы хотите быть более конкретным с 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);
}

Насколько я понял концепцию Delphi, у D нет ссылок на классы в Delphi. Если вам нужно принять во время выполнения решение о строительстве объекта, object.TypeInfo может помочь вам.

Вы можете получить TypeInfo для переменной через typeid построить:

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 работает во время компиляции и поэтому не может запрашивать "реальный" тип класса в случае иерархий.

Другие вопросы по тегам