Estaba pensando en el uso, typeid()
pero no sé cómo preguntar si ese tipo es una subclase de otra clase (que, por cierto, es abstracta)
c++
class
subclass
identification
Chad
fuente
fuente
std::is_base_of
no funcionará como se desea. : 3Respuestas:
Realmente no deberías. Si su programa necesita saber qué clase es un objeto, eso generalmente indica un defecto de diseño. Vea si puede obtener el comportamiento que desea usando funciones virtuales. Además, sería útil contar con más información sobre lo que está intentando hacer.
Supongo que tienes una situación como esta:
class Base; class A : public Base {...}; class B : public Base {...}; void foo(Base *p) { if(/* p is A */) /* do X */ else /* do Y */ }
Si esto es lo que tiene, intente hacer algo como esto:
class Base { virtual void bar() = 0; }; class A : public Base { void bar() {/* do X */} }; class B : public Base { void bar() {/* do Y */} }; void foo(Base *p) { p->bar(); }
Editar: Dado que el debate sobre esta respuesta aún continúa después de tantos años, pensé que debería incluir algunas referencias. Si tiene un puntero o referencia a una clase base y su código necesita conocer la clase derivada del objeto, entonces viola el principio de sustitución de Liskov . El tío Bob llama a esto un " anatema para el diseño orientado a objetos ".
fuente
class Base { public: virtual ~Base() {} }; class D1: public Base {}; class D2: public Base {}; int main(int argc,char* argv[]); { D1 d1; D2 d2; Base* x = (argc > 2)?&d1:&d2; if (dynamic_cast<D2*>(x) == nullptr) { std::cout << "NOT A D2" << std::endl; } if (dynamic_cast<D1*>(x) == nullptr) { std::cout << "NOT A D1" << std::endl; } }
fuente
dynamic_cast<>
aquí? ¿Nostatic_cast<>
sería suficiente?x
en tiempo de compilación? Si es asístatic_cast<>()
, funcionaría. Si no se puede saber el tipo dex
hasta el tiempo de ejecución, entonces usted necesitadynamic_cast<>()
Puedes hacerlo con
dynamic_cast
(al menos para tipos polimórficos).En realidad, pensándolo bien, no puede decir si es ESPECÍFICAMENTE un tipo en particular con,
dynamic_cast
pero puede decir si es ese tipo o alguna subclase del mismo.template <class DstType, class SrcType> bool IsType(const SrcType* src) { return dynamic_cast<const DstType*>(src) != nullptr; }
fuente
std::is_polymorphic_v<T>
seafalse
.El siguiente código muestra 3 formas diferentes de hacerlo:
#include <iostream> #include <typeinfo> #include <typeindex> enum class Type {Base, A, B}; class Base { public: virtual ~Base() = default; virtual Type type() const { return Type::Base; } }; class A : public Base { Type type() const override { return Type::A; } }; class B : public Base { Type type() const override { return Type::B; } }; int main() { const char *typemsg; A a; B b; Base *base = &a; // = &b; !!!!!!!!!!!!!!!!! Base &bbb = *base; // below you can replace base with &bbb and get the same results // USING virtual function // ====================== // classes need to be in your control switch(base->type()) { case Type::A: typemsg = "type A"; break; case Type::B: typemsg = "type B"; break; default: typemsg = "unknown"; } std::cout << typemsg << std::endl; // USING typeid // ====================== // needs RTTI. under gcc, avoid -fno-rtti std::type_index ti(typeid(*base)); if (ti == std::type_index(typeid(A))) { typemsg = "type A"; } else if (ti == std::type_index(typeid(B))) { typemsg = "type B"; } else { typemsg = "unknown"; } std::cout << typemsg << std::endl; // USING dynamic_cast // ====================== // needs RTTI. under gcc, avoid -fno-rtti if (dynamic_cast</*const*/ A*>(base)) { typemsg = "type A"; } else if (dynamic_cast</*const*/ B*>(base)) { typemsg = "type B"; } else { typemsg = "unknown"; } std::cout << typemsg << std::endl; }
El programa de arriba imprime esto:
fuente
dynamic_cast
puede determinar si el tipo contiene el tipo de destino en algún lugar de la jerarquía de herencia (sí, es una característica poco conocida que siB
hereda deA
yC
, puede convertir unaA*
directamente en aC*
).typeid()
puede determinar el tipo exacto del objeto. Sin embargo, ambos deben usarse con extrema moderación. Como ya se mencionó, siempre debe evitar la identificación dinámica de tipos, ya que indica un defecto de diseño. (Además, si sabe que el objeto es seguro del tipo de objetivo, puede hacer un abatimiento con unstatic_cast
. Boost ofrece unpolymorphic_downcast
que hará un abatimiento condynamic_cast
yassert
en modo de depuración, y en el modo de lanzamiento solo usará astatic_cast
).fuente
No estoy de acuerdo en que nunca debería querer verificar el tipo de un objeto en C ++. Si puede evitarlo, estoy de acuerdo en que debería hacerlo. Sin embargo, decir que NUNCA debes hacer esto bajo ninguna circunstancia es ir demasiado lejos. Puede hacer esto en muchos idiomas y puede hacer su vida mucho más fácil. Howard Pinsley, por ejemplo, nos mostró cómo en su publicación sobre C #.
Trabajo mucho con Qt Framework. En general, modelo lo que hago según la forma en que hacen las cosas (al menos cuando trabajan en su marco). La clase QObject es la clase base de todos los objetos Qt. Esa clase tiene las funciones isWidgetType () e isWindowType () como una verificación rápida de subclase. Entonces, ¿por qué no poder verificar sus propias clases derivadas, que son comparables en su naturaleza? Aquí hay un derivado de QObject de algunas de estas otras publicaciones:
class MyQObject : public QObject { public: MyQObject( QObject *parent = 0 ) : QObject( parent ){} ~MyQObject(){} static bool isThisType( const QObject *qObj ) { return ( dynamic_cast<const MyQObject*>(qObj) != NULL ); } };
Y luego, cuando pasa un puntero a un QObject, puede verificar si apunta a su clase derivada llamando a la función miembro estática:
if( MyQObject::isThisType( qObjPtr ) ) qDebug() << "This is a MyQObject!";
fuente
No sé si entiendo correctamente su problema, así que permítame repetirlo con mis propias palabras ...
Problema: Dadas las clases
B
yD
, determine siD
es una subclase deB
(¿o viceversa?)Solución: ¡Usa un poco de magia de plantilla! Bien, en serio, debes echar un vistazo a LOKI, una excelente biblioteca de metaprogramación de plantillas producida por el legendario autor de C ++ Andrei Alexandrescu.
Más específicamente, descargue LOKI e incluya el encabezado
TypeManip.h
en su código fuente y luego use laSuperSubclass
plantilla de clase de la siguiente manera:if(SuperSubClass<B,D>::value) { ... }
De acuerdo con la documentación,
SuperSubClass<B,D>::value
será verdadero siB
es una base pública deD
, o siB
yD
son alias del mismo tipo.es decir,
D
es una subclase deB
oD
es lo mismo queB
.Espero que esto ayude.
editar:
Tenga en cuenta que la evaluación de
SuperSubClass<B,D>::value
ocurre en tiempo de compilación a diferencia de algunos métodos que lo usandynamic_cast
, por lo tanto, no hay penalización por usar este sistema en tiempo de ejecución.fuente
#include <stdio.h> #include <iostream.h> class Base { public: virtual ~Base() {} template<typename T> bool isA() { return (dynamic_cast<T*>(this) != NULL); } }; class D1: public Base {}; class D2: public Base {}; class D22: public D2 {}; int main(int argc,char* argv[]); { D1* d1 = new D1(); D2* d2 = new D2(); D22* d22 = new D22(); Base* x = d22; if( x->isA<D22>() ) { std::cout << "IS A D22" << std::endl; } if( x->isA<D2>() ) { std::cout << "IS A D2" << std::endl; } if( x->isA<D1>() ) { std::cout << "IS A D1" << std::endl; } if(x->isA<Base>() ) { std::cout << "IS A Base" << std::endl; } }
Resultado:
fuente
Bueno, sí, se podría hacer mediante la comparación:
typeid().name()
. Si tomamos la situación ya descrita, donde:class Base; class A : public Base {...}; class B : public Base {...}; void foo(Base *p) { if(/* p is A */) /* do X */ else /* do Y */ }
Una posible implementación de
foo(Base *p)
sería:#include <typeinfo> void foo(Base *p) { if(typeid(*p) == typeid(A)) { // the pointer is pointing to the derived class A } else if (typeid(*p).name() == typeid(B).name()) { // the pointer is pointing to the derived class B } }
fuente
Solo puede hacerlo en tiempo de compilación usando plantillas, a menos que use RTTI.
Te permite usar la función typeid que producirá un puntero a una estructura type_info que contiene información sobre el tipo.
Leer sobre ello en Wikipedia
fuente
En c # puedes simplemente decir:
if (myObj is Car) { }
fuente
Puede hacerlo con plantillas (o SFINAE (La falla de sustitución no es un error)). Ejemplo:
#include <iostream> class base { public: virtual ~base() = default; }; template < class type, class = decltype( static_cast<base*>(static_cast<type*>(0)) ) > bool check(type) { return true; } bool check(...) { return false; } class child : public base { public: virtual ~child() = default; }; class grandchild : public child {}; int main() { std::cout << std::boolalpha; std::cout << "base: " << check(base()) << '\n'; std::cout << "child: " << check(child()) << '\n'; std::cout << "grandchild: " << check(grandchild()) << '\n'; std::cout << "int: " << check(int()) << '\n'; std::cout << std::flush; }
Salida:
base: true child: true grandchild: true int: false
fuente