2012-02-10 2 views
1

у меня есть класс со следующей структурой:переменного типа возвращаемого значения в C++ класса

class myClass 
{ 
    private: 
     int type; 
     classOne objectOne; 
     classTwo objectTwo; 
    public: 
     myClass(classOne object) 
     { 
      this->objectOne = object; 
      this->type = 0; 
     } 
     myClass(classTwo object) 
     { 
      this->objectTwo = object; 
      this->type = 1; 
     } 
} 

я теперь хочу метод, возвращающий объект типа classOne если тип 0 и типа classTwo если тип 1. Я не хотите, чтобы два метода достигли этого. классы имеют разные структуры.

Возможно ли это? Любые предложения приветствуются :)

+0

сделать '' classOne' и classTwo' имеют общую базу класс? – Flexo

+1

нет, есть совершенно другая структура, я добавлю это на вопрос – stefan

+0

Спасибо всем за ваши ответы. Я возьму простой способ и реализую два метода и проверю тип вручную. Я думал, что это может быть проще, просто имея один метод. – stefan

ответ

2

Вы можете использовать Boost.Variant для этого. Вариант может быть построен непосредственно из любого значения, конвертируемого в один из его ограниченных типов. Аналогично, варианту может быть присвоено любое значение, конвертируемое в один из его ограниченных типов. Вот как вы можете использовать его в своем классе:

class myClass 
{ 
    private: 
     boost::variant<classOne, classTwo> obj; 
    public: 
     myClass(classOne object) : obj(object) 
     { 
     } 
     myClass(classTwo object) : obj(object) 
     { 
     } 
}; 

Она также обеспечивает очень удобный boost::get для извлечения значения из варианта. Вы можете использовать это для подачи кода для каждого ограниченного типа, который у вас есть (т.е. classOne и classTwo). Вот пример:

if (classOne * x = boost::get<classOne>(&obj)) 
{ 
    //Code for classOne 
} 
else if (classTwo * x = boost::get<classTwo>(&obj) 
{ 
    //Code for classTwo 
} 

Однако такой код довольно хрупкий, и без пристального внимания, вероятно, приведет к введению тонких логических ошибок обнаруживаемых только во время выполнения. Таким образом, использование варианта в реальном мире обычно требует более надежного механизма доступа, чем get. По этой причине вариант поддерживает время, прошедшее проверку во время компиляции, через apply_visitor. Для посещения требуется, чтобы программист явно обрабатывал (или игнорировал) каждый ограниченный тип. Невыполнение этого условия приводит к ошибке времени компиляции.

Для посещения варианта требуется объект-посетитель. Как это:

class object_visitor 
: public boost::static_visitor<> 
{ 
public: 

    void operator()(classOne & x) const 
    { 
     //Code for classOne 
    } 

    void operator()(classTwo & x) const 
    { 
     //Code for classTwo 
    } 

}; 

При реализации вышеуказанного посетителя, мы можем применить его к obj, как показано в следующем:

boost::apply_visitor(object_visitor(), obj); 
2

Если эти два типа не связаны (в этом случае вы можете создать функцию, которая вернет указатель/ссылку на общего предка), вы не сможете сделать это непосредственно на C++.

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

В зависимости от конкретной задачи решить, могут быть различные подходы, которые вы могли бы принять, в том числе с использованием типа стирания (возврата boost::any, boost::variant или собственный типа стирания).

+0

'boost :: variant' на самом деле не стирает стили, это всего лишь тип безопасного объединения. – Xeo

+0

@Xeo: Вы находитесь прямо здесь. Я неправильно использовал этот термин. Во всяком случае, вам нужно преобразовать систему, чтобы иметь уникальный тип возврата, независимо от того, является ли это видовым объединением или стираемым объектом типа является деталь. –

1

ClassOne и ClassTwo должны иметь одинаковый тип возврата, либо через наследование или композицию. i.e ClassOne и ClassTwo должны быть подклассами одного и того же суперкласса, или им нужно использовать один и тот же интерфейс.

+0

Из любопытства: какая разница между реализацией одного и того же интерфейса и наследованием от базового класса? – Flexo

+0

Не то, чтобы я хотел зажечь дискуссию 1 по сравнению с другой, в которой лучше, но (imo), композиция позволяет гораздо больше использовать повторное использование кода, ремонтопригодность и позволяет масштабировать решение для расширения. – OnResolve

+0

Подсказка: на C++ нет такой вещи, как интерфейс - это Javaism – Flexo

0

Если они полностью разные структуры, без общей базы, альтернативный способ вернуть их из той же функции - использовать void*.

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

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

0

Использование идентификатора типа является признаком того, что вам нужны виртуальные функции для myClass. Даже если два других класса полностью независимы, тот факт, что они возвращаются одной и той же функцией, может легко заставить их наследовать базовый класс. А также вы можете просто вернуть пару, содержащую class1, class2, и одна из них может быть нулевой.

0

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

struct res { 
    myClass* c1; 
    ClassOne* c2; 
} ; 

Поле не выбранного класса NULL, в остальных точках на объект.

1

Я не уверен, почему вы не использовали шаблоны для своего дела.

Вы можете иметь что-то, как показано ниже:

template <class ClassType> 
class myClass 
{ 
    private: 
     int type; 
     ClassType object;    
    public: 
     myClass(ClassType object_in) 
     { 
      this->object = object_in; 
      /* 
       C++ doesn't support reflection so I don't think there 
       is a robust way of doing the following at runtime. 
      */ 
      type = /* Get Type at runtime */; 
     } 
     /* 
      Have another method which return object in a straigtforward way. 
     */ 
}; 

Однако, то это стало тривиальным. Чем больше вы узнаете, что такое ваш вариант использования, так что вам нужно знать тип?

Update: Если ClassType будет объект, вы можете иметь const static int TypeID элемент для класса, который устанавливается во время компиляции. Затем вы можете использовать его для определения типа во время выполнения.

+0

Я считаю, что автору вопроса требуется поведение во время выполнения, то есть код, вызываемый во время выполнения, будет либо для classOne, либо для classTwo , И шаблоны C++ разрешаются во время компиляции, поэтому они не могут помочь в этом случае. – paercebal

+0

Да. Следовательно, для достижения аналогичного поведения я упомянул, что TypeID необходимо будет установить во время компиляции заранее для всех используемых не-родных типов. – vvnraman

Смежные вопросы