Unique_ptr, определенный как базовый класс, затем преобразуется в производный класс

Я хотел бы видеть печать двух объектов из двух разных производных классов, и ключом к этому является приведение объекта к производному классу после его определения как базового. Вот код:

#include <iostream>
#include "memory"

using namespace std;

template<class T>
class Base
{
public:
    Base() {};
    ~Base() {};
    void Print()
    {
        std::cout << "Print from Base" << std::endl;
    }
};

class Derived1: public Base<int>
{
public:
    Derived1() {}
    void Print()
    {
        std::cout << "Print from Derived1" << std::endl;
    }
};

class Derived2: public Base<int>
{
public:
    Derived2() {}
    void Print()
    {
        std::cout << "Print from Derived2"<< std::endl;
    }
};

class user
{
public:
    user();
    user(int type)
    :m_type(type)
    {
        switch(type) // change should be done here?
        {
        case 1:
            m_ptr = make_unique<Derived1>(); // m_ptr still base? why not derived
            break;
        case 2:
            m_ptr = make_unique<Derived2>();;
            break;
        default:
            break;
        }
    }

    ~user() {};
    void UserPrint()
    {
        m_ptr->Print();
    }
private:
    std::unique_ptr<Base<int>> m_ptr;
    int m_type;
};

int main()
{
    user a(1);
    user b(2);

    a.UserPrint();
    b.UserPrint();

    return 0;
}

Я ожидаю увидеть

Print from Derived1
Print from Derived2

но вместо этого я вижу

Print from Base
Print from Base

Как изменить код, чтобы он работал? Я бы предпочел изменить конструктор user(int type).

Если вы не говорите нам ничего, ваша жизнь станет намного проще, если вы сделаете метод Printвиртуальным.

user4581301 29.08.2024 17:45

@ user4581301 Я полностью с тобой согласен :D

Nick X Tsui 29.08.2024 19:20

Совет по упрощению: class Base { public: void Print() { std::cout << "Print from Base\n"; } }; -- Нет необходимости иметь шаблон и нет необходимости определять ничего не делающий конструктор/деструктор. Чтобы сделать это еще проще, замените class на struct и отбросьте public:. Хотя эти детали могут иметь ценность в реальном коде, в этом примере они отвлекают внимание.

JaMiT 29.08.2024 21:43
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
3
56
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Я думаю, что у вас есть некоторое недопонимание относительно переопределения методов в C++, потому что вам не хватает виртуальных ключевых слов в (предполагаемых) виртуальных методах:

#include <iostream>
#include "memory"

using namespace std;

template<class T>
class Base
{
public:
    Base() {};
    ~Base() {};
    virtual void Print()
    {
        std::cout << "Print from Base" << std::endl;
    }
};

class Derived1: public Base<int>
{
public:
    Derived1() {}
    void Print() override
    {
        std::cout << "Print from Derived1" << std::endl;
    }
};

class Derived2: public Base<int>
{
public:
    Derived2() {}
    void Print() override
    {
        std::cout << "Print from Derived2"<< std::endl;
    }
};

class user
{
public:
    user();
    user(int type)
    :m_type(type)
    {
        switch(type) // change should be done here?
        {
        case 1:
            m_ptr = make_unique<Derived1>(); // m_ptr still base? why not derived
            break;
        case 2:
            m_ptr = make_unique<Derived2>();;
            break;
        default:
            break;
        }
    }

    ~user() {};
    void UserPrint()
    {
        m_ptr->Print();
    }
private:
    std::unique_ptr<Base<int>> m_ptr;
    int m_type;
};

int main()
{
    user a(1);
    user b(2);

    a.UserPrint();
    b.UserPrint();

    return 0;
}

Обратите внимание на использование ключевого слова override в производных Print. virtual является обязательным в базовом классе для работы переопределения, но override выдает ошибки, если метод должен переопределять, но по той или иной причине этого не делает. Например, простая опечатка: print не отменяет Print. Упс. Но если print помечен override, компилятор обнаружит ошибку.

user4581301 29.08.2024 17:58

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