2011-07-23 15 views
6

Como the QObject documentation y muchos otros explican, un QObject tiene una identidad y oculta su copia de constructor y operador de asignación.C++ Qt Reflection with Copy and Assignment

Sin embargo, no estoy derivando de QObject por su característica de propiedades dinámicas o la característica de señales/ranuras. Solo quiero reflexión, o la posibilidad de acceder a Foo::staticMetaObject.

class Foo : public QObject { 
    Q_OBJECT 
    Q_ENUMS(Color) 
public: 
    enum Color { Blue, Red, Pink }; 
private: 
    Color color; 
}; 

Q_DECLARE_METATYPE(Foo::Color) 

Entonces no puedo copiar Foo con:

Foo a; 
Foo b; 
a = b; 

¿Cuál es la mejor manera de permitir la copia y la asignación en este caso? ¿Debo absolutamente escribir un constructor de copias y un operador de asignación? ¿Cómo se verían? ¿La reflexión todavía funcionará?

+0

Quiere decir que no usa 'QObject'. Porque la reflexión no es la fuente del problema aquí. El problema es que QObject hace que la copia y la asignación sean privadas (por una buena razón). –

+1

@kristianp, buena sugerencia, haría esa edición * si * @alexisdm no proporcionó la respuesta exacta a mi pregunta exacta. Muchas veces la respuesta es "no hagas lo que pides", pero en este caso, incluso si esa es una respuesta razonable, también hay una que me permite hacer lo que quiero hacer: 'Q_GADGET' –

Respuesta

14

Si sólo está interesado en que la reflexión de

  • el nombre de clase,
  • enumeraciones y banderas (Q_ENUMS, Q_FLAGS),
  • información de clase (Q_CLASSINFO),

puede usar Q_GADGET instead of Q_OBJECT:

class Foo { 
    Q_GADGET 
    Q_ENUMS(Color) 
public: 
    enum Color { Blue, Red, Pink }; 
private: 
    Color color; 
}; 

que declarará y definirá Foo::staticMetaObject.

+0

Guau, yo no escuché de 'Q_GADGET' antes. Por lo tanto, parece ser una versión ligera y estática de 'Q_OBJECT' que puede ser muy útil en algunos casos (como este). Triste, no está documentado, al menos no pude encontrarlo. Esto lo convierte en no oficial y por lo tanto no está garantizado para funcionar en el futuro :( – leemes

+0

@leemes En realidad se menciona brevemente junto a 'Q_OBJECT' en la página' QObject' (agregué el enlace de arriba). Pero se puede decir que está bastante bien escondido, y solo lo encontré cuando buscaba en el código fuente de moc algo más. – alexisdm

1

No sé mucho sobre qt, pero si el constructor de copia no está permitido, entonces debe haber una razón para ello (que se explica en el enlace que publicó). Puede cambiar su diseño para no tenerlo.

Aún si insiste, entonces memcpy puede ser su último recurso. No lo recomiendo personalmente, porque tienes que preocuparte por la copia profunda, vtable, etc., que no siempre son triviales.

2

Sin duda puede implementar tanto un constructor de copia como un operador de asignación de copia en su clase derivada, pero es probable que sea un signo de mal diseño. Tome este ejemplo:

#include <iostream> 

class Base { 
public: 
    Base() {} 

private: 
    Base(const Base& other) { 
     std::cout << "Base copy constructor invoked!" << std::endl; 
    } 
}; 

class Derived : public Base { 
public: 
    Derived() {} 

    Derived(const Derived& other) { 
     std::cout << "Derived copy constructor invoked!" << std::endl; 
    } 
}; 

int main(int argc, char** argv) { 
    Derived a; 
    Derived b = a; 

    return 0; 
} 

Esto compilará muy bien. Sin embargo, como se esperaba, cuando ejecuta el programa resultante, todo lo que se imprime es Derived copy constructor invoked!. Cuando la clase base declara su operador de asignación de copia/constructor como privado, eso no impide que las clases derivadas implementen sus propias versiones. Simplemente impide que las clases derivadas invoquen las versiones de clase base.

Y ahí radica el problema: siempre es una buena práctica asegurarse de copiar todas las partes de un objeto, de modo que de hecho tenga dos copias distintas. Parte de su objeto incluye los datos propiedad de la clase base, por lo que siempre debe asegurarse de invocar el operador de asignación de copia/constructor de copia de la clase base para asegurarse de que se realiza una copia completa. Pero esos datos son, por diseño, no copiables. Por lo tanto, es imposible copiar todas las partes del objeto.

Depende de usted si desea seguir con este diseño. Una cosa importante que debes hacerte es, ¿tu clase derivada realmente necesita ser copiable? Si no, ¡entonces no hay nada de qué preocuparse!