2011-03-11 17 views
20

¿Puede una unión en C++ tener una función de miembro? ¿Cómo existe una unión con miembros de datos y funciones miembro si se crea un objeto?Unión en C++ son viables

Si supongo que sí, entonces son factibles en cualquier lugar. Si es así, ¿dónde?

Respuesta

31

9,5/1

Una unión puede tener funciones miembro (incluyendo constructores y destructores), pero no virtuales (10.3) funciones. Una unión no debe tener clases base . No se usará una unión como una clase base. Un objeto de una clase con un constructor no trivial (12.1), una copia constructor no trivial (12.8), un destructor no trivial (12.4), o un no trivial operador de asignación de copia (13.5. 3, 12.8) no puede ser miembro de un sindicato , ni puede un conjunto de tales objetos

¿Qué quiere decir por Cómo hacer la unión con los miembros de datos y las funciones miembro existir si se crea un objeto? Las funciones miembro (no virtual) no ocupan espacio en una instancia de cualquier clase/unión.

+1

+1, nunca pensé que podría hacer eso con los sindicatos. Aprende algo nuevo todos los días ... –

+0

+1 por algo que no sabía y escrito no solo porque "funciona para mí" – Flexo

0

No sé si es válido. Codepad acepta, los funcionamientos, y da la salida esperada de este programa

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

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

simplemente he añadido algunas cosas más para @maraguida ejemplo. Lo escribí como respuesta solo para tener más espacio. Ilustra que no solo se pueden agregar funciones miembro, sino también funciones miembro estáticas y operadores.

#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; 
} 

Puede ser compilado con: g ++ -Wall union_func.cpp -o union_func

La salida es:

$ ./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 

Puede, por ejemplo, poner un operador de conversión a otro tipo de su necesidad, si tiene sentido para su necesidad.

10

También se puede hacer una unión de plantilla:

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

El union es una estructura de C, y no funciona bien con los tipos de C++ (hay una serie de advertencias en realidad). Sin embargo, ya existe un equivalente en C++, que funciona con todas las clases de C++ y clases definidas por el usuario, ¡y es incluso más seguro que la unión!

Behold Boost.Variant!

Se puede definir una boost::variant<std::string, Foo, char> y va a asegurarse de que:

  • que el operador constructor/destructor/asignación apropiada se ejecuta, cuando sea necesario
  • que sólo se accede al valor lastest que se estableció

Y viene incluso con la excelente: boost::static_visitor<Result> que le permite aplicar un método en la unión, independientemente de su tipo, y proporcionar verificación en tiempo de compilación para advertirle cuando haya olvidado una de las posibles tipos!

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

también ... es tan eficiente (rápido) como un union, y no implica ninguna consulta dinámica como Boost.Any haría.