Как объявить объект из условия и сделать его доступным через остальную часть функции? - PullRequest
4 голосов
/ 29 ноября 2010

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

if (myapp.advanced == true)
    class1 a;
else
    class2 a;

Но так как a объявлен изнутри if, он не доступен в следующей строке. Как исправить вышеуказанное условие?

 a.something();

Ответы [ 5 ]

3 голосов
/ 29 ноября 2010

Два способа мыслить:

1) Сделайте class1 и class2 производными от некоторого базового класса classB, затем выполните:

shared_ptr<classB> a;
if(myapp.advanced == true) a.reset(new class1);
else a.reset(new class2);
a->something();

2) Написать шаблон функции:

template <typename T> void do_something(T& t)
{
  t.something();
}

...

if(myapp.advanced)
{
  class1 a;
  do_something(a);
}
else
{
  class2 a;
  do_something(a);
}

Обратите внимание, что второй подход больше подходит, если вы не можете изменить class1 и class2, чтобы добавить базовый класс. Я также предполагаю, что бит внутри do_something сложнее, чем просто вызов something() для рассматриваемого объекта - в противном случае вы можете просто вызвать его напрямую!

РЕДАКТИРОВАТЬ: просто чтобы уточнить, второй подход не делает его доступным для остальной части рассматриваемой функции - он добавляет новую функцию, в которой он доступен вместо.

2 голосов
/ 29 ноября 2010

Если эти типы связаны, используйте общий базовый класс и сделайте следующее:

const base& a = (myapp.advanced == true) ? static_cast<base&>(class1())
                                         : class2();
a.something();
a.some_other_thing();
a.yet_another_thing();

Временные привязки, привязанные к ссылке const, имеют время жизни, увеличенное до конца времени жизни ссылки, так что этобезопасный.Однако такая хакерская атака не понадобится (и вы можете покончить с const, если вам нужно изменить объект), если вы разделите задачи создание объекта и объект, использующий в различных функциях:

void do_something(base& obj)
{
  obj.something();
  obj.some_other_thing();
  obj.yet_another_thing();
}

if (myapp.advanced == true) {
    class1 a;
    do_something(a);
} else {
    class2 a;
    do_something(a);
}

Если типы не связаны, вы все равно можете сделать это, превратив do_something() в шаблоны функций:

template< class T >
void do_something(T& obj)
{
  obj.something();
  obj.some_other_thing();
  obj.yet_another_thing();
}

if (myapp.advanced == true) {
    class1 a;
    do_something(a);
} else {
    class2 a;
    do_something(a);
}
2 голосов
/ 29 ноября 2010

Ваша логика кодирования подразумевает, что Class1 и Class2 имеют что-то общее.Выразите это в коде, сделав их производными от общего базового класса.Затем используйте указатель базового класса для хранения экземпляров производных классов.

1 голос
/ 29 ноября 2010

Есть много способов подойти к этому, но без дополнительной информации я бы, вероятно, посоветовал вам сделать это:

Полагаю, у классов есть общий предок по имени Base

Base* a;
if (myapp.advanced == true)
    a = new class1();
else
    a = new class2();

Конечно, вы не должны забывать выдавать delete после того, как он вам больше не нужен или использовать умный указатель.

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

1 голос
/ 29 ноября 2010

Я бы порекомендовал поместить функцию something () как чисто виртуальный в базовый класс и наследовать от него class1 и class2.

class Base
{
public:
    virtual void something() = 0;
    virtual ~Base(){}; // since we use Base class pointer the destructor should be virtual
};

class class1 : public Base
{
public:
    void something(){ //do stuff
    }
};
class class2 : public Base
{
public:
    void something(){ //do other stuff
    }
};

Вот пример использования этой техники:

int main()
{    
    Base* a = NULL;

    if (myapp.advanced == true)
        a = new class1();
    else
        a = new class2();

    a->something();

    // when the instance is not needed anymore destroy it.
    delete a;
}

Как упоминал Фред Нурк в комментариях, есть и другие альтернативы использования оператора delete - auto_ptr, различные умные указатели для повышения.Они широко используются многими людьми (в том числе и мной), облегчая контроль жизни объектов, созданных с помощью new.

Еще одно редактирование после комментария ОП:
Не забудьте включить множественное включениемакрос защиты в ваших заголовках

#ifndef _SOME_UNIQUE_NAME_HERE_
#define _SOME_UNIQUE_NAME_HERE_

// header body goes here

#endif

, чтобы избежать многократного включения (прямого или косвенного) ваших заголовков в один cpp.

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