#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).