Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 22.01.2022, 03:51   #1
JeyP
Новичок
Джуниор
 
Регистрация: 22.01.2022
Сообщений: 3
По умолчанию ООП. Наследование и полиморфизм. Легкий вопрос от новичка.

Доброе время суток всем. Судьба заставила засесть за С++. Грызу гранит, и по пути стараюсь что-то писать. Помогите пожалуйста реализовать такую конструкцию (ниже код на Java, специально написал пример чтобы было понятно. Пояснений я думаю будет не нужно).

Есть абстрактный класс.

Код:
public abstract  class AbstractUser {                       //------ абстрактный класс
    private String myNick;                                  // ------ поле класса

    public String getMyNick() {return  myNick;};            // ------ геттер на это поле
    void setMyNick (String myNick) {this.myNick = myNick;}  // ------- сеттер на это поле
    public abstract String sayMyEntity();                   // ------ не реализовано. для наследника
}
Есть два наследника (ну или больше, не принципиально. главное что несколько)
Первый:
Код:
public class Human extends  AbstractUser{

    public Human() {super();}

    @Override
    public String sayMyEntity() {               //---- это реализация метода из родителя
       return "I'm a HUMAN "+this.getMyNick();  //---- this - ссылка именно на текущий экземпляр класса 
    }                                           //---- метод getMyNick полчается уже есть В ЭТОМ КЛАССЕ
}                                               //---- и по Ctrl+SPACE даже вываливается в списке подстановки
Второй аналогичный:
Код:
public class Computer extends  AbstractUser{

    public Computer() {super();}

    @Override
    public String sayMyEntity() {
        return "I'm a Computer "+this.getMyNick();
    }
}
Есть еще такой класс обвязка:
Код:
public class Dispatcher {
    private  AbstractUser think;              //----  поле содержит потомка AbstractUser

    public Dispatcher() {                     //----- Конструктор
        long i = System.currentTimeMillis();  //----- Надо случайно как-то заполнить поле чтобы было мало кода   
        if (i% 2 ==0)                         //----- Берем остаток от деления на 2 текщего времени
            {think = new Human();}            //----- создаем если ноль
        else
            {think = new Computer();}         //----- создаем если не ноль
        think.setMyNick(i+"");                //-----  тоже случайное что-то записал. не важно.
    }                                         //----- важно как обратился. Потому что я не знаю чей метод сработает.

    public String describeMe() {return think.sayMyEntity();} //-- тут тоже не знаю чей мето сработает.
    public AbstractUser getThink() {return this.think;}      //-- а тут просто возвращаю случайный класс-наследник
}
Ну и запуск программы:
Код:
 public class TestProgram {
    public static void main(String[] args) {
        Dispatcher disp;                                      //-------- локальная переменна диспетчер

        for (int i=0; i<100; i++)                             //-------- сто раз выведем
        {
           try{                                                     //-- колхозный способ поспать случайное время,
               Thread.sleep(System.currentTimeMillis()% 25);   //-- а то быстро очень. Тапками не кидать :)
            } catch (Exception e) {e.printStackTrace();}            //-- так просто наглядно, а смвсл не в этом

           disp = new Dispatcher();                                 // --- Создаем обьект в цикле сто раз

           System.out.println(disp.describeMe());                  //---- вытряхаем описание    
           System.out.println(disp.getThink().getMyNick());        //---- и ник (реализован аж в абстракте) 
        }

    }
}
Ну и результат частично:
Код:
I'm a HUMAN 1642811515198
1642811515198
I'm a HUMAN 1642811515222
1642811515222
I'm a Computer 1642811515245
1642811515245
I'm a HUMAN 1642811515274
1642811515274
I'm a Computer 1642811515299
1642811515299
.....
.....
.....

Весь день сегодня пытался аналогичную конструкцию наваять на С++. Видимо у меня какая то проблема с синтаксисом, или я совсем отупел уже на старости лет

Если не трудно, переведите мне мой пример на С++ только чтобы он точно работал, очень поможете сберечь мне нервы. Понятно что не надо никаких задержек , меня интересует именно обрщение к классам так же как у меня в коде. Спасибо.
(RTFM не предлагать, это первое что я делаю всегда)

Последний раз редактировалось JeyP; 22.01.2022 в 03:59.
JeyP вне форума Ответить с цитированием
Старый 22.01.2022, 08:31   #2
Алексей1153
фрилансер
Форумчанин
 
Регистрация: 11.10.2019
Сообщений: 960
По умолчанию

JeyP, что-то навроде https://onlinegdb.com/C3Bia9W1X
Код:
#include <iostream>
#include <string>
#include <memory>
#include <ctime>
#include <thread>
#include <chrono>

class AbstractUser
{
    std::string myNick;

public:
    std::string getMyNick() const {return  myNick;}
    void setMyNick (std::string_view myNick) {this->myNick = myNick;}
    
    virtual std::string sayMyEntity()const=0;
    virtual ~AbstractUser()=default;
};

class Human:public AbstractUser
{
public:
    std::string sayMyEntity()const override
    {
       return "I'm a HUMAN "+getMyNick();
    }
};

class Computer :public AbstractUser
{
public:
    std::string sayMyEntity()const override
    {
       return "I'm a Computer "+getMyNick();
    }
};

class Dispatcher
{
    std::unique_ptr<AbstractUser> think;

    public:
    Dispatcher()
    {
        uint64_t i = std::rand();
        if (i% 2 ==0)
        {
            //think = new Human;
            think = std::make_unique<Human>();
        }
        else
        {
            //think = new Computer;
            think = std::make_unique<Computer>();
        }
        
        think->setMyNick(std::to_string(i)+"");
    }

    public:
    std::string describeMe()const
    {
        if(!think)return {};
        return think->sayMyEntity();
    }
    
    //тут осторожно! - возвращается голый указатель.
    //Память по нему нельзя освобождать снаружи!
    //(если требуется другая логика, нужно переделать метод по ситуации)
    const AbstractUser* getThink()const
    {
        return think.get();
    }
};

int main()
{
    std::srand(std::time({}));
    
    for (int i=0; i<100; i++)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(50));
        
        Dispatcher disp;
        
        std::cout<<disp.describeMe()<<", ";
        if(auto* think=disp.getThink())
        {
            std::cout<<think->getMyNick();
        }
        else
        {
            std::cout<<"nullptr";
        }
        std::cout<<'\n';
    }
}

Последний раз редактировалось Алексей1153; 22.01.2022 в 08:35.
Алексей1153 на форуме Ответить с цитированием
Старый 22.01.2022, 08:39   #3
Алексей1153
фрилансер
Форумчанин
 
Регистрация: 11.10.2019
Сообщений: 960
По умолчанию

а чтобы случайное время спать, можно так сделать
Код:
std::this_thread::sleep_for(std::chrono::milliseconds(std::rand()%25));
Алексей1153 на форуме Ответить с цитированием
Старый 22.01.2022, 15:51   #4
JeyP
Новичок
Джуниор
 
Регистрация: 22.01.2022
Сообщений: 3
По умолчанию

Алексей1153, спасибо большое Вам большое. ВЫ СПАСИТЕЛЬ Сейчас буду пробовать. Идея понятна. Но теперь всплыли еще вопросы
В С++ деструкторы же есть (а слона то я и не приметил...). Жава то такими мелочами как память не заморачивается ))) (шутка)

1) Если я в диспетчере определю деструктор и вызову его снаружи класса (в данном случае из main), то грохнется ли у меня заодно экземпляр того что в think? В реальной задаче у меня просто массив think-ов, и у меня возникает сомнение что компилятор такой умный В жаве есть гарбаж коллектор он со временем удаляет все то на что потерян указатель. В С++ как я понял надо самому заморачиваться на эту тему.

2) Как я понимаю, имя деструктора фиксировано (т.е. свое нельзя). Если я в человеке и компьютере определю свои деструкторы (или надо переопределить абстрактный?) то как к ним правильно обратиться? Как мне грохнуть тот объект на который ссылается think из класса диспетчера (имена то деструкторов разные)

В реальном мире оперативка мне очень критична, думаю что наверное можно как-то заморочиться со своевременным удалением объектов.

Еще раз спасибо

Последний раз редактировалось JeyP; 22.01.2022 в 15:55.
JeyP вне форума Ответить с цитированием
Старый 22.01.2022, 17:53   #5
Алексей1153
фрилансер
Форумчанин
 
Регистрация: 11.10.2019
Сообщений: 960
По умолчанию

JeyP, деструктор всегда один. Идентификатор его начинается с тильды, затем идёт имя класса. Вручную деструктор нельзя вызывать (кроме одного, очень редкого и особенного случая, но этот случай нам тут не нужен).
Деструктор вызывается автоматически: для локальных переменных при выходе из области видимости, для динамических - при вызове delete

я использовал стандартную обёртку над сырым указателем std::unique_ptr, чтобы не писать деструктор вручную

эту обёртку можно попросить удалить объект методом release
Код:
think.release();
Алексей1153 на форуме Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Наследование и полиморфизм C# Алиса_М Помощь студентам 1 03.05.2016 12:29
Объясните пожалуйста программу. показать 3 основных признака ООП: наследование, инкапсуляция, полиморфизм (Паскаль) mongush Помощь студентам 11 27.01.2014 16:52
наследование и полиморфизм в ооп IRONHIDE C++ Builder 1 29.01.2013 12:39
ООП (наследование и полиморфизм) Shadow94 Общие вопросы C/C++ 4 21.11.2011 00:01
ОоП полиморфизм ... наследование ... Xsires Общие вопросы Delphi 2 04.09.2011 15:38