Шаблоны против полиморфизма

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

class Genome { // Interface
    // Some abstract functions 
}

class SpecificGenome : public Genome {
    // implementation
public:   
    int do_something(int x); // Specific behavior, which only this SpecificGenome has
}

class Population {
public:
    Population(size_t population_size, std::function<std::unique_ptr<Genome>()> create_genome);
    // Some functions
    std::vector<std::unique_ptr<Genome>> members;
}

std::unique_ptr<Genome> create_specific_genome(){
    return std::unique_ptr<Genome>(std::make_unique<SpecificGenome>());
}

int main() {
    Population p(150, &create_specific_genome);

    int y = static_cast<SpecificGenome>(*p.members[0].get())->do_something(4);
}

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

Редактировать: Вопрос в его нынешнем виде очень неясен, поэтому я хотел добавить некоторые дополнительные пояснения. Я хочу иметь возможность создать популяцию с любым типом генома (NeuralNetwork, NEAT Genome, изображение, ...), поэтому я сделал это, используя интерфейс и подклассы, чтобы вектор в популяции мог хранить каждый тип, используя указатель генома. Это было полезно, потому что каждый тип генома должен иметь определенные методы, такие как скрещивание и мутация. Проблема возникает, когда я хочу использовать определенные функции, такие как вычисление вывода нейронной сети, декодирование генома или получение пиксельных данных изображения, декодирование генома. Это заставило меня задаться вопросом, будет ли лучше использовать шаблоны вместо наследования.

@ Рон есть. Он может добавлять разных потомков Genome к members

Marek R 06.05.2019 17:27

Так это только называется полиморфизмом, если в векторе есть несколько типов геномов?

user10847213 06.05.2019 17:30

"поли" по-гречески означает "много" afaik. В вашем коде нет "многих". Наличие указателя не делает его полиморфным

463035818_is_not_a_number 06.05.2019 17:31

@DerEistee, можете ли вы предоставить больше кода? Похоже контекста не хватает и описание тоже не очень понятное.

Marek R 06.05.2019 17:31

@MarekR хорошо, я добавлю немного

user10847213 06.05.2019 17:32

«Поэтому каждый геном должен быть приведен пользователем к соответствующему подклассу, чтобы раскрыть его поведение, что выглядит очень уродливо». это кажется «проблемой», которую вы пытаетесь избежать. Предоставьте минимальный воспроизводимый пример, демонстрирующий эту проблему. В текущем коде нечего исправлять

463035818_is_not_a_number 06.05.2019 17:33

почему doSomething не является частью интерфейса? То есть почему doSomething не метод Genome ?

463035818_is_not_a_number 06.05.2019 17:47

Возможно, шаблон «Метод шаблона» может быть вам полезен.

acarlstein 06.05.2019 17:52

«Несколько типов геномов» в каком смысле? Что именно вы здесь моделируете? Как полиморфизм помогает вашей библиотеке?

Konrad Rudolph 06.05.2019 17:52
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
9
123
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Шаблон может помочь вашему делу лучше, но имеет другое значение.

Например, ваш список не может быть разнородным по типу генома, который он содержит. Все должно быть одного типа. Если вам нужна неоднородность, вам придется реализовать какое-то стирание типов.

Вот пример, похожий на ваш пример, но со статическим полиморфизмом:

// no inheritance
class SpecificGenome {
public:   
    int do_something(int x);
}

template<typename G, typename C>
class Population {
public:
    Population(size_t population_size, C create_genome);

    // no need for pointers. Values work just fine.
    std::vector<G> members;
}

// Deduction guide using the create_genome function return type
template<typename C>
Population(std::size_t, C) -> Population<std::invoke_result_t<C>, C>;

SpecificGenome create_specific_genome() {
    return SpecificGenome{};
}

int main() {
    // Uses class template argument deduction
    Population p(150, create_specific_genome);

    int y = p.members[0].do_something(4);
}

Кстати, если вы все еще используете std::unique_ptr, вы можете использовать его с гораздо лучшим синтаксисом:

std::unique_ptr<Genome> create_specific_genome() {
    // no need for casts
    return std::make_unique<SpecificGenome>();
}

// no need for calls to `get`.
int y = static_cast<SpecificGenome&>(*p.members[0]).do_something(4);

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