Как преодолеть нарезку объектов в шаблоне репозитория?

У меня есть следующий фрагмент кода:

#include <iostream>

class AnimalRepository {
public:
    virtual ~AnimalRepository() = default;

    virtual auto makeSound() -> void {
        std::cout << "Null" << std::endl;
    }

};

class CatRepository: public AnimalRepository {
public:
   
    auto makeSound() -> void override {
       std::cout << "Meow" << std::endl;
    }

};

class DogRepository: public AnimalRepository {
public:

    auto makeSound() -> void override {
        std::cout << "Woof" << std::endl;
    }

};

class Animal {
public:
    explicit Animal(const AnimalRepository& repository)
            : repository(repository) {
    }

    auto makeSound() -> void {
        return repository.makeSound();
    }

protected:
    AnimalRepository repository;
};

Animal cat = Animal(CatRepository());

Animal dog = Animal(DogRepository());

int main() {
    cat.makeSound();
    dog.makeSound();
};

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

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

Some programmer dude 05.01.2023 11:50
auto cat = std::make_unique<Animal>(Cat());
jxh 05.01.2023 11:51

вы вызываете Animal::makeSound, который вызывает repository::makeSound, который печатает Null. Непонятно, почему вы ожидали чего-то другого. Нарезки объектов нет (пока?), но вам нужны ссылки или указатели для динамической отправки. Но, пожалуйста, опубликуйте реальный код. Код, который вы опубликовали, не производит никакого вывода, потому что он не компилируется godbolt.org/z/q3WYz1fKs

463035818_is_not_a_number 05.01.2023 11:51

Также кажется, что вы что-то упустили из-за ООП и наследования в своих книгах. Animal cat = Animal(Cat()); тоже не имеет смысла.

Some programmer dude 05.01.2023 11:51

о Animal(Cat()); на самом деле это нарезка объектов

463035818_is_not_a_number 05.01.2023 11:52

@Someprogrammerdude, это измененный пример того, что я пытаюсь сделать, переименованы только объекты, методы и переменные. Я бы предпочел просто сосредоточиться на проблеме, а не углубляться в семантику дизайна, так как это уже решено за меня и не изменится.

spiklespacklespokle 05.01.2023 11:53
Animal::makeSound не является виртуальным. В вашем коде много непонятного. Чтобы получить помощь, вы должны по крайней мере опубликовать код, который компилирует и производит вывод, о котором вы сообщаете. Читайте о минимальном воспроизводимом примере
463035818_is_not_a_number 05.01.2023 11:55

@ 463035818_is_not_a_number у меня отлично компилируется. Единственное, что изменилось, это имена объектов, которые не должны иметь значения. Именно так и написано.

spiklespacklespokle 05.01.2023 11:55

кстати AnimalRepository::makeSound является виртуальным, но ничего не наследует от него

463035818_is_not_a_number 05.01.2023 11:56
godbolt.org/z/TM4jWreMf
463035818_is_not_a_number 05.01.2023 11:57

Вы, кажется, перепутали Animal с AnimalRepository. Это объяснило бы многое.

Some programmer dude 05.01.2023 11:58

@ 463035818_is_not_a_number ничего не изменилось, кроме имен классов. Я не знаю, что тебе сказать. Я ничего не получаю от постулирования невоспроизводимого примера, поэтому просто игнорируйте его. Спасибо

spiklespacklespokle 05.01.2023 11:58

Ошибка @Someprogrammerdude при изменении имен для этого примера, проблема остается. Хотя спасибо за улов

spiklespacklespokle 05.01.2023 11:59

Кажется, у вас тоже очень похожее задание, как у этого вчерашнего вопроса.

Some programmer dude 05.01.2023 12:00

Вместо использования AnimalRepository repository я бы использовал AnimalRepository* repository (и очищал вручную) или std::unique_ptr<AnimalRepository> repository. Я подозреваю, что именно здесь происходит нарезка

Den-Jason 05.01.2023 12:04

Когда вы сохраняете в AnimalRepository repository;, остается место только для базового класса, поэтому эта часть сохраняется. Остальное потеряно. Это не имеет ничего общего с передачей параметров или чем-то еще, это просто то, как работает хранение.

BoP 05.01.2023 12:04

@Someprogrammerdude не уверен, так как я не заинтересован в использовании карты, и у этого есть отдельная цель

spiklespacklespokle 05.01.2023 12:04

Карта или вектор или другой контейнер не имеет значения. И теперь ваш дизайн имеет еще меньше смысла. Помните, что наследование — это отношение «является». Является ли «собака» действительно «хранилищем животных»? «Хранилище животных» - это место, где так или иначе хранится несколько животных, а не животное само по себе. Я действительно призываю вас вернуться к своим учебникам, чтобы освежиться, возможно, даже пойти к своему учителю и попросить ее или его о помощи.

Some programmer dude 05.01.2023 12:09
Стоит ли изучать 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
18
68
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Нарезка делается здесь: AnimalRepository repository;. Это не может содержать подкласс, потому что это экземпляр, а не ссылка или указатель. Проще всего заменить его уникальным интеллектуальным указателем, указывающим на копию ввода.

Или переместите весь шаблон из динамического полиморфизма в (время компиляции) статический полиморфизм.

#include <iostream>

class CatBehavior 
{
public:

    auto makeSound() -> void 
    {
        std::cout << "Meow" << std::endl;
    }

};

class DogBehavior 
{
public:

    auto makeSound() -> void 
    {
        std::cout << "Woof" << std::endl;
    }
};

template<typename behavior_t>
class Animal 
{
public:
    explicit Animal() 
    {
    }

    auto makeSound() -> void 
    {
        return m_behavior.makeSound();
    }

protected:
    behavior_t m_behavior;
};

int main() 
{
    Animal<CatBehavior> cat;
    Animal<DogBehavior> dog;

    cat.makeSound();
    dog.makeSound();
};

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