Squeak.ru - шаблоны программирования

D: Наследование статических переменных, дифференциация по классам?

Я работаю над ситуацией, когда я хотел бы иметь определенный базовый класс, который определяет статический ассоциативный массив и статические функции, которые с ним работают, а затем дублировать эту функциональность в классах, которые наследуются от него, но с каждым дочерним классом, имеющим собственный экземпляр массива. Однако похоже, что дочерние классы просто наследуют родительский массив, а не создают свою собственную статическую копию, как я надеялся. Ниже приведена супер-упрощенная урезанная версия того, что я надеялся выполнить:

class MyBase {
    static string[string] dict;
    static void attach(string key, string val) {
        dict[key] = val;
    }
}
class MySubA : MyBase {
    // various unique member variables
}
class MySubB : MyBase {
    // ...
}
void main() {
    MySubA.attach("a", "a1");
    MySubB.attach("b", "b1");
    writefln("-:%s", MyBase.dict);
    writefln("A:%s", MySubA.dict);
    writefln("B:%s", MySubB.dict);
}

Желаемый результат:

-:[]
A:["a":"a1"]
B:["b":"b1"]

Фактический результат:

-:["a":"a1", "b":"b1"]
A:["a":"a1", "b":"b1"]
B:["a":"a1", "b":"b1"]

Есть ли способ обойти это, не отказываясь от наследования и просто дублируя соответствующий код для каждого подкласса? Фактический код для назначения массиву, с которым я работаю, более сложен, чем просто функция присоединения, указанная выше, поэтому я хотел бы избежать необходимости дублировать его каждый раз или присваивать .dict вручную, если это необходимо. Мне интересно, есть ли решение с использованием шаблонов, которое могло бы работать, но я просто не могу собрать его воедино.


Ответы:


1

Статическая переменная в классе является частью этого класса и только частью этого класса. Во всей программе существует один его экземпляр, независимо от того, сколько экземпляров этого класса было создано или сколько классов было получено из него. Статические переменные-члены не наследуются больше, чем обычные переменные-члены. Производные классы имеют доступ к базовой переменной, если она общедоступна или защищена, но они не получают свою собственную копию. Ничего не копируется в цепочке производных классов. Переменные-члены существуют в классе, в котором они объявлены, а производные классы потенциально имеют к ним доступ, но производные классы не получают свою собственную копию.

Таким образом, помещая dict в MyBase, вы создаете один из них для всей своей программы, независимо от того, что делают его производные классы. Если вы хотите, чтобы каждый из ваших производных классов имел свою собственную копию, тогда каждый из них должен будет объявить свою собственную копию.

Теперь вы можете свести к минимуму дублирование кода с помощью миксина шаблона или миксина строки, но вам все равно придется смешивать его с каждым производным классом. Например, вы можете сделать это

import std.stdio;

mixin template Dict()
{
    static string[string] dict;
    static void attach(string key, string val)
    {
        dict[key] = val;
    }
}

class MyBase
{
    mixin Dict;
}

class MySubA : MyBase
{
    mixin Dict;
    // various unique member variables
}

class MySubB : MyBase
{
    mixin Dict;
    // ...
}

void main()
{
    MySubA.attach("a", "a1");
    MySubB.attach("b", "b1");
    writefln("-:%s", MyBase.dict);
    writefln("A:%s", MySubA.dict);
    writefln("B:%s", MySubB.dict);
}
17.07.2012

2

Ах, похоже, я только что наткнулся на решение.

class MyBase(T) {
    static string[string] dict;
    static void append(string key, string val) {
        dict[key] = val;
    }
}
class MySubA : MyBase!MySubA {
    // various unique member variables
}
class MySubB : MyBase!MySubB {
    // ...
}

делает именно то, что я хотел. Размещение собственного ответа в соответствии с быстрым поиском этикета.

17.07.2012
  • Просто чтобы вы знали, MySubA и MySubB таким образом не используют один и тот же базовый класс. Они находятся в совершенно разных иерархиях классов, поскольку MyBase!MySubA и MyBase!MySubB — это разные классы. Различные экземпляры одного и того же шаблона являются совершенно отдельными объектами, не связанными друг с другом. 17.07.2012
  • И если иерархия классов на самом деле не требуется (и используется только для обеспечения реализации dict), то я бы сказал, что шаблонный миксин - это путь. 18.07.2012
  • +1 Определенно. @ccjuju, если вы используете только наследование, чтобы избежать небольшого дублирования, не используйте дженерики. Если, с другой стороны, эти классы представляют иерархию объектов, то опубликованное вами решение не делает того, о чем вы просили. 18.07.2012

  • 3

    Если вам не нужна иерархия:

    import std.stdio;
    
    mixin template Dict()
    {
        static string[string] dict;
        static void attach(string key, string val)
        {
            dict[key] = val;
        }
    }
    
    class MySubA
    {
        mixin Dict;
    }
    
    class MySubB
    {
        mixin Dict;
    }
    
    void main()
    {
        MySubA.attach("a", "a1");
        MySubB.attach("b", "b1");
        writefln("A:%s", MySubA.dict);
        writefln("B:%s", MySubB.dict);
    }
    

    Я думаю, что это лучшее решение, чем это наследование шаблонов.

    23.07.2012
    Новые материалы

    Угловая структура архитектуры
    Обратите внимание, что эта статья устарела, я решил создать новую с лучшей структурой и с учетом автономных компонентов: https://medium.com/@marekpanti/angular-standalone-architecture-b645edd0d54a..

    «Данные, которые большинство людей используют для обучения своих моделей искусственного интеллекта, поставляются со встроенным…
    Первоначально опубликовано HalkTalks: https://hacktown.com.br/blog/blog/os-dados-que-a-maioria-das-pessoas-usa-para-treinar-seus-modelos-de-inteligencia-artificial- ja-vem-com-um-vies-embutido/..

    Сильный ИИ против слабого ИИ: различия парадигм искусственного интеллекта
    В последние годы изучению и развитию искусственного интеллекта (ИИ) уделяется большое внимание и прогресс. Сильный ИИ и Слабый ИИ — две основные парадигмы в области искусственного интеллекта...

    Правильный способ добавить Firebase в ваш проект React с помощью React Hooks
    React + Firebase - это мощная комбинация для быстрого и безопасного создания приложений, от проверки концепции до массового производства. Раньше (знаете, несколько месяцев назад) добавление..

    Создайте API с помощью Python FastAPI
    Создание API с помощью Python становится очень простым при использовании пакета FastAPI. После установки и импорта вы можете создать приложение FastAPI и указать несколько конечных точек. Каждой..

    Веселье с прокси-сервером JavaScript
    Прокси-серверы JavaScript — это чистый сахар, если вы хотите создать некоторую общую логику в своих приложениях, чтобы облегчить себе жизнь. Вот один пример: Связь клиент-сервер Мы..

    Получить бесплатный хостинг для разработчиков | Разместите свой сайт за несколько шагов 🔥
    Статические веб-сайты — это веб-страницы с фиксированным содержанием и его постоянным содержанием. Но теперь статические сайты также обрабатывают динамические данные с помощью API и запросов...