Nous avons un sous-projet 'CommonUtils' qui possède de nombreux extraits de code génériques utilisés dans le projet parent. Une de ces choses intéressantes que j'ai vues était la suivante: -
class PolyBase { public: virtual ~PolyBase(){} }; class NPolyBase { public: ~NPolyBase(){} }; if (isPolymorphic<PolyBase>()) std::cout<<"PolyBase = Polymorphic\n"; if (isPolymorphic<NPolyBase>()) std::cout<<"NPolyBase = Also Polymorphic\n";
5 Réponses :
class PolyBase { public: virtual ~PolyBase(){} }; class NPolyBase { public: ~NPolyBase(){} }; template<class T> struct IsPolymorphic { struct Derived : T { virtual ~Derived(); }; enum { value = sizeof(Derived)==sizeof(T) }; }; void ff() { std::cout << IsPolymorphic<PolyBase >::value << std::endl; std::cout << IsPolymorphic<NPolyBase>::value << std::endl; }
Je ne suis pas sûr que cela soit complètement résistant. Un compilateur peut ajouter du rembourrage entre les sous-objets au cours de laquelle la taille de la taille de la taille () ne fonctionnerait pas.
Cela se briserait quand, disons que le dérivé définit ses propres variables de membre, ce qui la rend impraticable.
@Indeera: Vous n'ajoutez pas de variables de membre car la structure dérivée dérivée intentionnellement de la classe que vous spécifiez. La seule mise en garde est que la classe spécifiée ne possède pas de DTOR virtuel, mais certains funcs virtuels (au cours de quelle classe spécifiée sont toujours polymorphes) à part le problème du rembourrage. Boost suppose qu'une classe polymorphe définit un dteur virtuel et gère le rembourrage en utilisant des spécificités du compilateur que je suppose.
@Abhay: que toutes les classes polymorphes a une destructor virtuelle n'est pas la seule mise en garde; encore - selon votre premier commentaire, il repose sur l'optimisation de la classe de base vide aussi.
Cela ne fonctionne tout simplement pas avec la plupart des compilateurs. Il retournera false code> même si la classe testée a des fonctions virtuelles, si la classe étant testée a également des bases virtuelles quelque part dans sa hiérarchie.
Je ne peux pas imaginer une manière possible comment ce typeid pourrait être utilisé pour vérifier que le type est polymorphe. Il ne peut même pas être utilisé pour affirmer que c'est que Typeid fonctionnera sur n'importe quel type. Boost a une implémentation ici . Quant à la raison pour laquelle cela pourrait être nécessaire - un cas je sais est la bibliothèque Boost.Séralisation. Si vous épargnez de type non polymorphe, vous pouvez simplement l'enregistrer. Si vous épargnez polymorphe, vous devez obtenir son type dynamique à l'aide de typeID, puis invoquer la méthode de sérialisation pour ce type (la regarder dans une table).
update strong>: il apparaît que je suis vraiment faux . Considérez cette variante: P> template <class T>
bool isPolymorphic() {
bool answer=false;
T *t = new T();
typeid(answer=true,*t);
delete t;
return answer;
}
Oui, je connais la mise en œuvre de Boost qui utilise grossièrement la technique Tailleof (). Merci pour la série de sérialisation. J'étais intéressé par la connaissance si ce modèle CommunUtils est d'abord correct et deuxièmement, cela vaut la peine d'être préservé dans le projet.
Ah Ha, une astuce intéressante en effet, mais votre citation du 3.10 / 6 était éclairante, merci. On peut choisir sur la version templatunée lorsque la taille du binaire est importante ou si l'utilisateur ne doit pas faire confiance à la fourniture d'un DTor virtuel dans une classe polymorphe. Hélas je ne peux pas uplifier 2 fois!
Je suis un peu confus ici et j'espère avoir des commentaires sur cette réponse expliquant ce qui me manque.
Sûrement si vous voulez savoir si une classe est polymorphe, tout ce que vous avez à faire est Demandez si cela prend en charge dynamic_cast code>, n'est-ce pas? P>
template<class T, class> struct is_polymorphic_impl : false_type {};
template<class T> struct is_polymorphic_impl
<T, decltype(dynamic_cast<void*>(declval<T*>()))> : true_type {};
template<class T> struct is_polymorphic :
is_polymorphic_impl<remove_cv_t<T>, void*> {};
Depuis C ++ 11, il est maintenant disponible dans l'en-tête ceci imprime juste "polybase = polymorphe". P> p>
STD :: IS_POLYMORPHIC CODE>. Il peut être utilisé comme ceci:
On peut utiliser les faits qui:
dynamic_cast code> échoue au moment de la compilation si l'argument n'est pas une classe polymorphe. Afin qu'il puisse être utilisé avec Sfinae. LI>
-
dynamic_cast code> est une distribution valide qui renvoie l'adresse de l'objet complet em> polymorpique. li>
OL> Par conséquent, en C ++ 11: P>
#include <iostream>
#include <type_traits>
template<class T>
auto is_polymorphic2_test(T* p) -> decltype(dynamic_cast<void*>(p), std::true_type{});
template<class T>
auto is_polymorphic2_test(...) -> std::false_type;
template<class T>
using is_polymorphic2 = decltype(is_polymorphic2_test<T>(static_cast<T*>(0)));
struct A {};
struct B { virtual ~B(); };
int main() {
std::cout << is_polymorphic2<A>::value << '\n'; // Outputs 0.
std::cout << is_polymorphic2<B>::value << '\n'; // Outputs 1.
}
ER, si l'auteur est un programmeur senior C ++, pourquoi ne vérifiez-vous pas d'abord avec lui? ... vous apprendrez souvent beaucoup de gars expérimentés.
Eh bien, si je pouvais je ne l'aurais pas demandé sur Stackoverflow :-)