#c #pointers #casting #polymorphism
#c #указатели #Кастинг #полиморфизм
Вопрос:
Вот в чем проблема: у меня есть исходный код, который, если он заполнен операторами if / else, предназначен для выполнения одних и тех же инструкций, но в данных с другим типом. Мне это не нравится, и я хотел бы создать абстракцию для этого другого типа данных, таким образом, чтобы я мог установить правильный тип данных, а затем выполнить те же инструкции. Идея состоит в том, чтобы удалить все операторы if / else, которые загрязняют код. Ну, я много искал, и, похоже, решением моей проблемы была работа с полиморфизмом. Итак, мы здесь. Выше приведен заголовок классов, которые я создал для выполнения полиморфизма. Этот, Platform, является базовым классом, а два других, Vero и Pionner, являются производными.
#ifndef VEHICLE_H
#define VEHICLE_H
#include <ros/ros.h>
#include <geometry_msgs/Twist.h>
#include <ransac_project/CarCommand.h>
class Platform{
public:
virtual void setmsg(const double amp;, const double amp;) = 0;
//X m_msg; //Some king of genetic type
};
class Vero: public Platform{
public:
ransac_project::CarCommand m_msg;
Vero();
void setmsg(const double amp;velocity, const double amp;steering);
};
class Pionner: public Platform{
public:
geometry_msgs::Twist m_msg;
Pionner();
void setmsg(const double amp;linear_vel, const double amp;angular_vel);
};
#endif /* VEHICLE_H */
В основном, у меня есть что-то вроде этого:
Platform* platform;
if(which_car.compare("vero")==0){
Vero vero; platform = amp;vero;
platform = static_cast<Vero*>(platform);
}
else{
Pionner pionner; platform = amp;pionner;
platform = static_cast<Pionner*>(platform);
}
Пока все хорошо. Но, после того, как где-то еще есть:
int a=0;
int b=0;
platform->setmsg(a,b); //WORKS
platform->m_msg; //DOES NOT WOTK
Ну, последнее утверждение не работает, потому что базовый класс не имеет переменной-члена m_msg, и я не могу ее создать, потому что ее тип варьируется в производных классах. Я также читал о шаблоне и указателе void, но не смог найти решение. На самом деле с указателем void я мог бы сделать что-то вроде этого:
void* platform;
if(which_car.compare("vero")==0){
Vero vero; platform = amp;vero;
}
else{
Pionner pionner; platform = amp;pionner;
}
static_cast<Vero*>(platform)->m_msg;
Но это, по сути, не решило бы мою проблему, поскольку я явно указываю тип в процессе приведения.
Есть простое решение этой проблемы? Любой другой подход к этой проблеме приветствуется.
Спасибо
Комментарии:
1.
Vero vero; platform = amp;vero;
Указатель зависает, как толькоif()
остается блок.2. В классе Vero и классе Pionner setmsg() также определяется как виртуальный, так что абстрактная функция-член setmsg() переопределяется
3. Фабричный метод — это еще один способ решить проблему типа путем регистрации унаследованных объектов и предварительного назначения соответствующих функций-членов
Ответ №1:
Если m_msg
в производных классах могут быть разные типы, они не могут существовать в базовом классе. (Или, скорее, это было бы скрыто m_msg
объявленным в производных классах.)
Даже если бы это произошло, компилятор не смог бы определить его тип во время компиляции, поэтому он понятия не имел бы, что делать с оператором
platform->m_msg; //DOES NOT WOTK
Как вы сказали, для решения этой проблемы можно использовать шаблоны. void
указатели также работают, но, учитывая их недостаточную безопасность типов, я не могу рекомендовать их, если альтернативный подход не будет работать.
Кроме того, m_
используется для указания переменных-членов, которые обычно являются частными, поэтому вам все равно не следует использовать его таким образом.
Кроме того, этот блок:
Platform* platform;
if(which_car.compare("vero")==0){
Vero vero; platform = amp;vero;
platform = static_cast<Vero*>(platform);
}
else{
Pionner pionner; platform = amp;pionner;
platform = static_cast<Pionner*>(platform);
}
Это проблема, и она должна вызывать некоторые предупреждения. В частности, в блоке, подобном этому:
{
Vero vero; platform = amp;vero;
platform = static_cast<Vero*>(platform);
}
{...}
определите локальную область видимости.
Вы создаете новый Vero
, присваиваете ему адрес platform
, затем vero
освобождается в конце блока, оставляя platform
в качестве висячего указателя. (Для получения дополнительной информации см. Статью Wiki о висячих указателях.)
Кроме того, оператор
platform = static_cast<Vero*>(platform);
Почему вы назначаете платформу самой себе? Это бесполезно.
Комментарии:
1. Исходный код немного отличается, фактически переменные платформы являются переменными-членами другого класса. В любом случае, у вас есть какие-либо предложения о том, как я могу решить эту проблему?
2. @Randerson шаблон
setmsg
в базовом классе, общем базовом классе или интерфейсе для ваших типов сообщений.