Не может использовать методы подкласса Y после его ввода в std::stack (C )

#c #class #c 11 #stack #subclass

#c #класс #c 11 #стек #подкласс

Вопрос:

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

Теперь, очевидно, std::stack в него можно помещать только элементы одного и того же типа, поэтому я создал очень общий Obj класс, который будет родительским классом для всех других типов данных, таких как Num , Chr , и т.д…

 class Obj
{
    std::string type;

    public:
    void set_type(std::string type) { this->type = type; }
    std::string get_type() { return this->type; }
};
 

Чтобы дать вам пример Num подкласса:

 class Num : public Obj
{
    double value;

    public:
    Num (double value)
    {
        this->set_type("num");
        this->value = value;
    }

    double get_value() { return this->value; }
};
 

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

 std::stack<Obj> data;

void emit_const(std::stack<Obj> amp;data)
{
    if ( data.empty() ) return; // some error checking

    std::string type = data.top().get_type();

    if (type == "bln")
    {
        Bln bln = data.top(); data.pop();
        std::cout << bln.get_value() ? "true" : "false";
    }

    else if (type == "chr")
    {
        Chr chr = data.top(); data.pop();
        std::cout << chr.get_value();
    }

    // ... and so on for the rest of the types
}
 

Когда я попытался скомпилировать это, компилятор GNU g выдал мне ошибку:

 conversion from ‘__gnu_cxx::__alloc_traits<std::allocator<Obj> >::value_type {aka Obj}’ 
to non-scalar type ‘Bln’ requested
         Bln bln = data.top(); data.pop();
 

Это же сообщение об ошибке выдавалось для каждой строки кода, где я в основном пытаюсь интерпретировать Obj как его подкласс, например Bln , или Num для того, чтобы иметь возможность использовать их методы, которые не определены в общем Obj классе.

Как я понимаю, после ввода любого экземпляра Obj подкласса, подобного Bln этому, в std::stack<Obj> этот экземпляр удаляются его методы и члены, которые не объявлены в родительском Obj классе (я сделал вывод, основываясь на том факте, что строка std::string type = data.top().get_type(); не генерирует ошибку). Такое поведение является разумным с точки зрения C . Тем не менее, мне все еще нужно заставить эту вещь работать, и мне нужно иметь возможность использовать методы этих элементов, когда они будут извлечены. Пожалуйста, помогите мне решить эту проблему эффективным способом! Заранее спасибо.

Если вы хотите взглянуть на общий макет кода: репозиторий GitHub

Комментарии:

1. Откройте свою книгу по C на главе, в которой объясняется, как работают методы виртуального класса, а также учебное пособие по интеллектуальным указателям в вашей книге по C . Ваш стек должен быть стеком std::unique_ptr или std::shared_ptr s для вашего родительского класса (который должен иметь виртуальный деструктор), и вы будете использовать методы своих дочерних классов в качестве виртуальных методов. Вам предстоит многому научиться, чтобы полностью понять, как работают эти передовые концепции C . Удачи.

2. Другим ключевым термином для поиска является нарезка объектов .

Ответ №1:

Здесь есть две проблемы: get_type он должен быть виртуальным, и когда вы используете std::stack<Obj> его, он удаляет все данные.

При использовании std::stack<Obj> он сначала преобразует его в объект Obj и удаляет все свойства num . Когда вы пытаетесь вернуть его к исходному типу, он не может, потому что он хранит только свойства Obj, а не информацию о подклассах. Чтобы исправить это, вы должны либо сохранить ссылку на него ( std::stack<Objamp;> ), либо сделать его копию и сохранить ее в куче ( std::stack<std::unique_ptr<Obj>> ), чтобы он мог сохранять информацию из подклассов.

Во-вторых, вам нужно объявить get_type как virtual . Virtual — это ключевое слово, которое указывает классу хранить информацию, указывающую, к какому типу она относится. Это позволяет программе вызывать правильный метод. Если вы не используете это, вместо этого всегда будет вызываться версия родительских классов (Obj).