Объединение указателей объектов (используйте только один тип для разных экземпляров) - PullRequest
0 голосов
/ 06 февраля 2020

Теперь у меня есть следующий фрагмент кода в классе:

DrvClassA *drv_a_obj;
DrvClassB *drv_b_obj;
DrvClassC *drv_c_obj;

if ( use_drv_a ) {
   drv_a_obj = new DrvClassA(args);
}
if ( use_drv_b ) {
   drv_b_obj = new DrvClassB(args);
}
if ( use_drv_c ) {
   drv_c_obj = new DrvClassC(args);
}

и я хочу каким-то образом преобразовать его, чтобы использовать только одну переменную для созданного экземпляра драйвера:

   this->Drv = new DrvClassA(args);
}
if ( use_drv_b ) {
   this->Drv = new DrvClassB(args);
}
if ( use_drv_c ) {
   this->Drv = new DrvClassC(args);
}

Я думал о создании такого объединения, но получаю ошибки при компиляции.

error: cannot convert 'DrvClassA*' to 'MainClass::DRIVERS*' in assignment

union DRIVER {
      DrvClassA *drv_a_obj;
      DrvClassB *drv_b_obj;
      DrvClassC *drv_c_obj;
}

DRIVER *Drv;

Это как-то достижимо? Чего мне не хватает?

Ответы [ 3 ]

2 голосов
/ 06 февраля 2020

Да, у вас может быть объединение указателей.

Что мне не хватает?

Вы не смогли указать, какого члена объединения назначить. Правильный синтаксис:

this->Drv->drv_a_obj = new DrvClassA(args);

PS Возможно, вас позже заинтересует, кто из членов профсоюза был назначен. Вы обнаружите, что это невозможно. Решением для этого является использование тегового объединения, такого как std::variant.

PPS: возможно, лучшим вариантом было бы использование наследования. this->Drv может быть указателем на базовый объект вместо объединения.

PPPS Не используйте собственные указатели. Вы получите утечки памяти и неопределенное поведение. Вместо этого используйте контейнеры RAII и умные указатели.

2 голосов
/ 06 февраля 2020

То, что вы можете искать, это полиморфизм :

Живой образец

class Drv{
    public:
    virtual ~Drv(){};
};

class DrvClassA : public Drv{};
class DrvClassB : public Drv{};
class DrvClassC : public Drv{};

int main(){  
    Drv* a = new DrvClassA(); // Drv a = DrvClassA();
    Drv* b = new DrvClassB(); // Drv b = DrvClassB();
    Drv* c = new DrvClassC(); // Drv c = DrvClassC();
}

Еще лучше использовать умные указатели, чтобы избежать утечек памяти :

Живой сэмпл

#include <memory>

using std::unique_ptr;

class Drv{
    public:
    virtual ~Drv(){};
};

class DrvClassA : public Drv{};
class DrvClassB : public Drv{};
class DrvClassC : public Drv{};

int main(){ 
    unique_ptr<Drv> a(new DrvClassA);
    unique_ptr<Drv> b(new DrvClassB);
    unique_ptr<Drv> c(new DrvClassC);
}
1 голос
/ 06 февраля 2020

union в основном требуется только для реализации variant.

Так что вы можете использовать:

using DRIVER = std::variant<std::unique_ptr<DrvClassA>,
                            std::unique_ptr<DrvClassB>,
                            std::unique_ptr<DrvClassC>>;

// or
//using DRIVER = std::variant<DrvClassA*, DrvClassB*, DrvClassC*>;

с использованием

DRIVER Drv;
// ...
Drv = std::make_unique<DrvClassA>(args);
// ...
std::visit(overloaded{[](const std::unique_ptr<DrvClassA>& ptr){ ptr->funcA(); },
                      [](const auto& ptr){ ptr->common_interface(); }}, // DrvClassB or DrvClassC
           Drv);

Но полиморфизм может быть более подходящим:

struct DRIVER
{
    virtual ~DRIVER() = default;
    virtual void some_common_function() = 0;
};
struct DrvClassA : DRIVER
{
    void some_common_function() override { /*..*/ }
};
struct DrvClassB : DRIVER
{
    void some_common_function() override { /*..*/ }
};
struct DrvClassC : DRIVER
{
    void some_common_function() override { /*..*/ }
};

, а затем

std::unique_ptr<DRIVER> Drv;
// ...
Drv = std::make_unique<DrvClassA>(args);

Drv->some_common_function();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...