Подтвердить что ты не робот

Союз в С++ - это возможно

Может ли объединение в С++ иметь функцию-член? Как объединение с элементами данных и функциями-членами существует, если объект создан?

Если я предполагаю, что да, тогда они возможны где угодно. Если да, то где?

4b9b3361

Ответ 1

9,5/1

Объединение может иметь функции-члены (включая конструкторы и деструкторы), но не виртуальные (10.3) функции. Союз не имеет базы классы. Союз не должен использоваться как базовый класс. Объект класса с нетривиальным конструктором (12.1), нетривиальный конструктор копии (12.8), нетривиальный деструктор (12.4) или нетривиальный оператор присваивания копии (13.5.3, 12.8) не может быть членом объединение, и не может быть массив таких Объекты

Что вы подразумеваете под Как объединение с членами данных и функциями-членами существует, если объект создан? Функции-члены (не виртуальные) не занимают места в экземпляре любого класса/объединения.

Ответ 2

Вы также можете создать объединение шаблонов:

template <typename T>
union Foo {
public:
  Foo() {}
  Foo(const T& value) : _val(value) {}

  const char* data() const {
    return _tab;
  }

  std::size_t size() const {
    return sizeof(T);
  }

  char operator[](unsigned int index) const {
      return _tab[index];
  }

private:
  T _val;
  char _tab[sizeof(T)];
}

Ответ 3

union является C-структурой и не работает с типами С++ (на самом деле существует несколько предостережений). Однако уже существует эквивалент С++, который эффективно работает со всеми классами С++ и определенными пользователем классами и даже безопаснее, чем объединение!

Вот Boost.Variant!

Вы можете определить boost::variant<std::string, Foo, char>, и он будет уверен:

  • что выполняется соответствующий оператор конструктора/деструктора/присваивания, когда требуется
  • что вы получаете доступ только к последнему установленному значению

И он даже поставляется с отличным: boost::static_visitor<Result>, который позволяет применять метод на объединении независимо от его типа и обеспечивать проверку времени компиляции, чтобы предупреждать вас, когда вы забыли один из возможных типов!

class MyVisitor: boost::static_visitor<int>
{
public:
  int operator()(std::string const& s) const {
    return boost::lexical_cast<int>(s);
  }

  int operator()(Foo const& f) const { return f.getAsInt(); }

  int operator()(char c) const { return c; }
};

typedef boost::variant<std::string, Foo, char> MyVariant;

int main(int argc, char* argv[]) {
  MyVariant v; // the std::string is constructed

  if (argc % 2) { v = Foo(4); }
  if (argc % 3) { v = argv[1][0]; }
  if (argc % 5) { v = argv[1]; }

  std::cout << boost::apply_visitor(MyVisitor(), v) << '\n';
  return 0;
}

Кроме того, он является эффективным (быстрым) как union и не требует какого-либо динамического поиска, такого как Boost.Any.

Ответ 4

Я не знаю, действительно ли это. Codepad принимает, запускает и дает ожидаемый результат из этой программы

union x {
  int t;
  int k() { return 42;};
};

int main() {
  x y;
  y.t = y.k();
  std::cout << y.t << std::endl;
}

Ответ 5

Я добавил еще несколько вещей в пример @maraguida. Я написал это как ответ, чтобы больше места. Он иллюстрирует, что могут быть добавлены не только функции-члены, но также статические функции-члены и операторы.

#include    <iostream>

union x
 {
    int     t;
    float   f;

    int k( )        { return t * 42;};
    static int static_k( )  { return 42;};

    float k_f( )    { return f * 42.0f;};

    unsigned char operator []( unsigned int );
};

unsigned char x::operator []( unsigned int i )
{
    if ( i >= sizeof( x ) )
        return  0;

    return  ( ( unsigned char * )&t )[ i ];
}

int main( )
{
    x   y;
    y.t = x::static_k( );

    std::cout << "y.t\t= " << y.t << std::endl;
    std::cout << "y.f\t= " << y.f << std::endl;
    std::cout << "y.k( )\t= " << y.k( ) << std::endl;
    std::cout << "x::static_k( )\t= " << x::static_k( ) << std::endl;
    std::cout << "y.k_f( )\t= " << y.k_f( ) << std::endl;

    std::cout << "y[ 0 ]\t= " << ( unsigned int )y[ 0 ] << std::endl;
    std::cout << "y[ 1 ]\t= " << ( unsigned int )y[ 1 ] << std::endl;
    std::cout << "y[ 2 ]\t= " << ( unsigned int )y[ 2 ] << std::endl;
    std::cout << "y[ 3 ]\t= " << ( unsigned int )y[ 3 ] << std::endl;
}

Его можно скомпилировать с помощью:   g++ -Wall union_func.cpp -o union_func

Вывод:

$ ./union_func 
y.t     = 42
y.f     = 5.88545e-44
y.k( )  = 1764
x::static_k( )  = 42
y.k_f( )        = 2.47189e-42
y[ 0 ]  = 42
y[ 1 ]  = 0
y[ 2 ]  = 0
y[ 3 ]  = 0

Вы можете, например, поместить оператор преобразования в другой тип вашей потребности, если это имеет смысл для вашей потребности.