En primer lugar, el sistema LLVM es extremadamente específico y en absoluto un reemplazo directo para el sistema RTTI.
Local
- Para la mayoría de las clases, no es necesario para generar información de RTTI
- Cuando se requiera, la información sólo tiene sentido dentro de una jerarquía dada
- Nos impide múltiples herencia de este sistema
Identificación de una clase de objeto
Tome una jerarquía simple, por ejemplo:
struct Base {}; /* abstract */
struct DerivedLeft: Base {}; /* abstract */
struct DerivedRight:Base {};
struct MostDerivedL1: DerivedLeft {};
struct MostDerivedL2: DerivedLeft {};
struct MostDerivedR: DerivedRight {};
Vamos a crear una enumeración específica a esta jerarquía, con un miembro de la enumeración de cada uno de los miembro de la jerarquía que se pueden crear instancias (las otras tendrían inútil).
enum BaseId {
DerivedRightId,
MostDerivedL1Id,
MostDerivedL2Id,
MostDerivedRId
};
Entonces, la clase Base
será reforzado con un método que devuelva esta enumeración.
struct Base {
static inline bool classof(Base const*) { return true; }
Base(BaseId id): Id(id) {}
BaseId getValueID() const { return Id; }
BaseId Id;
};
Y cada clase concreta es aumentado también, de esta manera:
struct DerivedRight: Base {
static inline bool classof(DerivedRight const*) { return true; }
static inline bool classof(Base const* B) {
switch(B->getValueID()) {
case DerivedRightId: case MostDerivedRId: return true;
default: return false;
}
}
DerivedRight(BaseId id = DerivedRightId): Base(id) {}
};
Ahora, es posible, simplemente, para consultar el tipo exacto, para la fundición.
ocultación de detalles de implementación
Tener los usuarios murking con getValueID
sería problemático, sin embargo, por lo que en este LLVM está escondida con el uso de métodos classof
.
Una clase determinada debe implementar dos métodos classof
: uno para su base más profunda (con una prueba de los valores adecuados de BaseId
) y uno para sí mismo (optimización pura). Por ejemplo:
struct MostDerivedL1: DerivedLeft {
static inline bool classof(MostDerivedL1 const*) { return true; }
static inline bool classof(Base const* B) {
return B->getValueID() == MostDerivedL1Id;
}
MostDerivedL1(): DerivedLeft(MostDerivedL1Id) {}
};
De esta manera, se puede comprobar si un yeso es posible o no a través de las plantillas:
template <typename To, typename From>
bool isa(From const& f) {
return To::classof(&f);
}
Imagínese por un momento que To
es MostDerivedL1
:
- si
From
es MostDerivedL1
, luego invocamos la primera sobrecarga de classof
, y funciona
- si
From
es cualquier otra cosa, luego invocamos la segunda sobrecarga de classof
, y la verificación usa la enumeración para determinar si el tipo concreto coincide.
Espero que sea más claro.
¿Es esta una pregunta de C# o C++? –
@Will: Buena captura. Tenía las etiquetas completamente equivocadas –
aplausos.¿Has echado un vistazo a la fuente de las plantillas? –