Я пишу библиотеку для генетических алгоритмов/нейроэволюции. В настоящее время программа использует полиморфизм, чтобы разрешить несколько типов геномов. Итак, мой код выглядит так:
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, изображение, ...), поэтому я сделал это, используя интерфейс и подклассы, чтобы вектор в популяции мог хранить каждый тип, используя указатель генома. Это было полезно, потому что каждый тип генома должен иметь определенные методы, такие как скрещивание и мутация. Проблема возникает, когда я хочу использовать определенные функции, такие как вычисление вывода нейронной сети, декодирование генома или получение пиксельных данных изображения, декодирование генома. Это заставило меня задаться вопросом, будет ли лучше использовать шаблоны вместо наследования.
Так это только называется полиморфизмом, если в векторе есть несколько типов геномов?
"поли" по-гречески означает "много" afaik. В вашем коде нет "многих". Наличие указателя не делает его полиморфным
@DerEistee, можете ли вы предоставить больше кода? Похоже контекста не хватает и описание тоже не очень понятное.
@MarekR хорошо, я добавлю немного
«Поэтому каждый геном должен быть приведен пользователем к соответствующему подклассу, чтобы раскрыть его поведение, что выглядит очень уродливо». это кажется «проблемой», которую вы пытаетесь избежать. Предоставьте минимальный воспроизводимый пример, демонстрирующий эту проблему. В текущем коде нечего исправлять
почему doSomething не является частью интерфейса? То есть почему doSomething не метод Genome ?
Возможно, шаблон «Метод шаблона» может быть вам полезен.
«Несколько типов геномов» в каком смысле? Что именно вы здесь моделируете? Как полиморфизм помогает вашей библиотеке?





Шаблон может помочь вашему делу лучше, но имеет другое значение.
Например, ваш список не может быть разнородным по типу генома, который он содержит. Все должно быть одного типа. Если вам нужна неоднородность, вам придется реализовать какое-то стирание типов.
Вот пример, похожий на ваш пример, но со статическим полиморфизмом:
// 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);
@ Рон есть. Он может добавлять разных потомков
Genomeкmembers