Доступ к методу производного класса из метода базового класса без виртуальных функций во время выполнения - PullRequest
0 голосов
/ 14 апреля 2011

У меня есть следующий пример кода. Один базовый класс и два производных класса, каждый со своими функциями (соответственно, function1 и function2). Ни function1, ни function2 не являются виртуальными в базовом классе. Я не могу изменить это, так как эти классы уже реализованы.

#include <iostream>    
class Base
{
public:
    Base(){}
    Base(int val) : m_base(val){}
    virtual ~Base(){}
    //base class methods
private:
    int m_base;
};

class Derived1 : public Base
{
public:
    Derived1(int val) : m_derived1(val){}
    ~Derived1(){}
    void print1(){std::cout << "Using Derived 1 class method" << std::endl;};
private:
    int m_derived1;
};

class Derived2 : public Base
{
public:
    Derived2(int val) : m_derived2(val){}
    ~Derived2(){}
    void print2(){std::cout << "Using Derived 2 class method" << std::endl;};
private:
    int m_derived2;
};

Я сейчас пытаюсь добиться следующего. Я хочу решить во время выполнения, какой производный класс я хочу использовать. Более того, я хотел бы вызвать их из метода базового класса, используя только объект b. В противном случае мне пришлось бы переписывать свою программу для каждой опции, которую я позволяю ввести во время выполнения (на практике у меня есть довольно много классов, из которых я могу выбирать).

int main()
{
    int option;
    std::cin >> option;

Base* b = new Base(5);

Derived1* d1 = new Derived1(5);
Derived2* d2 = new Derived2(5);

d1->print1(); //obviously this works
d2->print2(); //obviously this works

//In reality I thus have a function in d1 and d2 which is not present in b
//I have to decide on runtime which class I need to use

if(option == 1)
{
    b = d1;
}
else if(option == 2)
{
    b = d2;
}

/*
Rest of program ...
    b->invokeMethod;
    // ... //
    b->invokeMoreMethods;
*/

//Call derived functions on base object

//b->print1(); //fails obviously
if(option == 1)
{
    dynamic_cast<Derived1*>(b)->print1(); //will work if option == 1 is specified (*)
}
if(option == 2)
{
    dynamic_cast<Derived2*>(b)->print2(); //will work if option == 2 is specified (*)
}

return 0;
}

Можно ли сделать строки кода (*) без цикла if (option == 1) и if (option == 2)? Я не могу использовать какую-либо виртуальную функциональность, поскольку она не реализована ... Есть ли более элегантные решения этой проблемы?

1 Ответ

1 голос
/ 14 апреля 2011

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

Взлом с помощью std :: / boost :: function:

int main() {
    Base * b = 0;                    // You were leaking a Base object here
    boost::function< void () > f;
    ...
    if ( option == 1 ) {
       Derived1 d1 = new Derived1;   // Only instantiate the object you will use
       b = d1;
       f = boost::bind( &Derived1::print1, d1 );
    } else if ( option == 2 ) {
       Derived2 d2 = new Derived2;
       b = d2;
       f = boost::bind( &Derived2::print2, d2 );
    }
    ...
    f(); // will call either d1->print1(), or d2->print2()
    ...
    delete b;                      // should really use a smart pointer but I left
                                   // the raw pointer to minimize changes
}

Обратите внимание, что это неприятный трюк, и его будет трудно поддерживать довольно легко.

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