C++中的联合体是否可行?

22

C++中的联合(Union)可以有成员函数吗?如果创建了一个对象,带有数据成员和成员函数的联合如何存在?

如果我假设是可以的,那么它们是否随处可行?如果是,那么在哪里?

5个回答

33

联合体可以拥有成员函数(包括构造函数和析构函数),但不能拥有虚函数(10.3)。联合体不得具有基类。联合体不能被用作基类。一个具有非平凡构造函数(12.1)、非平凡复制构造函数(12.8)、非平凡析构函数(12.4)或非平凡赋值运算符(13.5.3,12.8)的类的对象不能成为联合体的成员,也不能是此类对象组成的数组的成员。

在创建一个实例时,如何存在带有数据成员和成员函数的联合体?成员函数(非虚函数)在任何类/联合体实例中不占用空间。


1
+1,我从来不知道你可以用联合体做到这一点。每天都会学到新东西... - Dave Rager
对于我不知道的东西+1,并且不仅仅是“对我有效”。 - Flexo

10
您可以创建一个模板联合:

您可以创建一个模板联合:

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)];
}

1

union是C结构,与C++类型不兼容(实际上有许多注意事项)。然而,已经存在一个C++等效版本,可以有效地处理所有C++类和用户定义的类,甚至比union更安全!

请看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 那样涉及任何动态查找。


0

我不知道它是否有效。Codepad接受、运行并从该程序中得到了预期的输出。

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

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

0

我刚刚在@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

例如,如果对您有意义,您可以将转换运算符放置到另一种类型中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接