2014-10-02 3 views
0

У меня есть класс Foo с частным союза:Getter для частного союза - C++

class Foo 
{ 
    public: 
    static Foo foo(int type); 
    static Foo foo(double type); 
    static Foo foo(bool type); 
    static Bar getBar(Foo foo); 
    private: 
    union Bar 
     { 
      int iBar; 
      double rBar; 
      bool bBar; 
     } bar; 
}; 

Могу ли я написать универсальный поглотитель, который возвращает соответствующий бар?

Я пробовал:

Bar Foo::getBar(Foo foo) 
    { 
    return foo.bar; 
    } 

и другие варианты, но компилятор не распознает тип под названием «Бар» в «Foo».

+0

ошибка: имя неизвестного типа «Бар» с каратом, указывающее на тип «Бар» в файле заголовка. – MayNotBe

+0

Проверьте обновленный ответ. Это то, что вы хотите? – gsamaras

+0

Я просто сделал. Никогда не слышал о кортеже - сейчас проверьте его – MayNotBe

ответ

2

две вещи - в отличие от данных и членов несильно, типы члены должны быть объявлены до их использования, и вы должны полностью определить вложенный тип в определениях вне-класса:

class Foo { 
    // here, compiler doesn't yet know what Bar is 
    union Bar { 
     int iBar; 
     double rBar; 
     bool bBar; 
    } bar; // now it does 
public: 
    static Bar getBar(Foo); // so use it 
}; 

    Foo::Bar Foo::getBar(Foo foo) { return foo.bar; } 
// ^^^^^ 

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

+2

Хорошая точка, но союзный бар все еще остается * частным * типом Foo. – Fox

+0

Игнорирование попытки внешнего использования типа частного члена класса, upvote для фактического ответа на вопрос. – Serge

+0

@Fox. В этом случае [отлично,] (http://coliru.stacked-crooked.com/a/f2cc1a5f16e453a8), потому что он получает доступ только от другого члена Foo. Наверное, не то, что хочет OP, да. – jrok

0

Использовать tuple.

Пример:

// tuple's get 
#include <iostream> 
#include <tuple> 

int main() 
{ 
    std::tuple<int,char> mytuple (10,'a'); 

    std::get<0>(mytuple) = 20; 

    std::cout << "mytuple contains: "; 
    std::cout << std::get<0>(mytuple) << " and " << std::get<1>(mytuple); 
    std::cout << std::endl; 

    return 0; 
} 

Обратите внимание, что если у вас есть два элемента, вы могли бы использовать std::pair.

В обновленном вопросе, необходимо направить объявить союз Bar, как это:

class Foo { 
    union Bar; 
public: 
    static Foo foo(int type); 
    static Foo foo(double type); 
    static Foo foo(bool type); 
    static Bar getBar(Foo foo); 
private: 
    union Bar { 
    int iBar; 
    double rBar; 
    bool bBar; 
    } bar; 
}; 

Кроме того, что вы делаете это не приемлемо, потому что bar является частным членом Foo.


Обратите внимание, что кортеж и объединение не являются точно такими же. «Tuple - это тип данных, содержащий несколько значений. Объединение может содержать одно значение одного типа за раз». Это означает, что данные кортежа могут сосуществовать, а данные объединения не могут.


Таким образом, в случае, если вы не хотите использовать кортеж, но придерживаться союза, вам необходимо изменить свой класс и сделать объединение видимым для остальной части мира. Теперь, когда он является частным, даже когда вы его получаете, с функцией getter, мир вне вашего класса не может видеть союз, поэтому он не может его использовать. Но тогда дело становится немного сложным, поэтому я не понимаю, почему бы не использовать кортеж.


Хороший пример для профсоюзов можно найти here. Он находится в C, как и ожидалось, поскольку Unions чаще встречаются в C, чем в C++.

+2

Эх, союз ничем не похож на кортеж. – jrok

+0

Не могли бы вы объяснить, почему @jrok? :) – gsamaras

+1

Tuple - это тип данных, содержащий несколько значений. Объединение может удерживать одно значение одного типа за раз. – jrok

0

Чтобы расширить ответ G.Samaras, вы имеете право сделать это:

typedef std::tuple<type0, type1, type2, type3, type4> MyTuple; 
MyTuple myTuple; 
type0 a = std::get<0>(myTuple); 
type1 b = std::get<1>(myTuple); //...etc. 

(редактировать: глупо меня ... как это получается, вы также можете этого сделать:

type0 a = std::get<type0>(myTuple); 
type1 a = std::get<type1>(myTuple); 

... оставляя остальную часть ответа на месте, как пример того, как НЕ считать вещи)

Итак, как вы связываете 0 с типом0 и так далее?Вы можете сделать это (проверялось, но должно работать):

class MyTupleWrapper 
{ 
    private: 
    template <typename T> class TypeOffset {}; 
    template <> class TypeOffset<type0> { enum { value = 0; } }; 
    template <> class TypeOffset<type1> { enum { value = 1; } }; 
    template <> class TypeOffset<type2> { enum { value = 2; } }; 
    template <> class TypeOffset<type3> { enum { value = 3; } }; 
    template <> class TypeOffset<type4> { enum { value = 4; } }; 
    // ...etc 
    public: 
    typedef std::tuple<type0, type1, type2, type3, type4> MyTupleType; 
    explicit MyTupleWrapper(const MyTupleType& type) : _type(type) {} 
    template <typename T> 
    const T& Get() { return std::get< TypeOffset<typename T>::value >(_type); } 
    private: 
    MyTupleType _type; 
} 

Чтобы разорвать эту конструкцию вниз, не заходя слишком много в реализации, то это:

а. У вас есть два инструмента - специализированный тип std::tuple<Type1, Type2, ...> и std::get<integer>(tupleObject);, чтобы получить от него определенные типы. Целочисленный параметр зависит от начального способа определения кортежа ... поэтому, если ваш номер равен 3, возвращаемое значение является третьим типом в вашем списке типов внутри этого кортежа (в нашем случае type3)

b. Кортеж сам по себе поддерживает нормальное назначение ... так разрешено MyTupleType t; t = type1();. Но вы не можете вызывать type1 a = t; - это должно быть type1 a = std::get<1>(t);, что глупо, потому что у вас может быть много типов кортежей, и вам не нужно будет помнить, какую позицию вы определили type1 в каждом типе.

c. Что делает эта оболочка (намеревается сделать?) - это способность сказать type1 a = t.Get<type1>(); с использованием перегрузки шаблонов для преобразования каждого типа в время компиляции в его смещение.

+0

Было бы неплохо, если бы вы представили пример, который использует ваш класс. :) – gsamaras

+0

действительно? downvoting из-за этого ?? – Fox

+0

Я проигнорирован, потому что это расширение ответа (это не кажется мне ответом) (http://stackoverflow.com/questions/26162556/getter-for-private-union-c#comment41017416_26162623). Также, чтобы продлить ответ, вы должны оставить комментарий, а не другой ответ. – Shoe