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

#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 в базовом классе, общем базовом классе или интерфейсе для ваших типов сообщений.