@@ -605,6 +605,8 @@ class Object {
605605 MESH_INSTANCE_3D = 1 << 14 ,
606606 };
607607
608+ static constexpr AncestralClass static_ancestral_class = (AncestralClass)0 ;
609+
608610 struct Connection {
609611 ::Signal signal;
610612 Callable callable;
@@ -790,6 +792,8 @@ class Object {
790792
791793 bool _disconnect (const StringName &p_signal, const Callable &p_callable, bool p_force = false );
792794 void _define_ancestry (AncestralClass p_class) { _ancestry |= (uint32_t )p_class; }
795+ // Prefer using derives_from.
796+ bool _has_ancestry (AncestralClass p_class) const { return _ancestry & (uint32_t )p_class; }
793797
794798 virtual bool _uses_signal_mutex () const ;
795799
@@ -821,16 +825,12 @@ class Object {
821825 static T *cast_to (Object *p_object) {
822826 // This is like dynamic_cast, but faster.
823827 // The reason is that we can assume no virtual and multiple inheritance.
824- static_assert (std::is_base_of_v<Object, T>, " T must be derived from Object" );
825- static_assert (std::is_same_v<std::decay_t <T>, typename T::self_type>, " T must use GDCLASS or GDSOFTCLASS" );
826- return p_object && p_object->is_class_ptr (T::get_class_ptr_static ()) ? static_cast <T *>(p_object) : nullptr ;
828+ return p_object && p_object->derives_from <T>() ? static_cast <T *>(p_object) : nullptr ;
827829 }
828830
829831 template <typename T>
830832 static const T *cast_to (const Object *p_object) {
831- static_assert (std::is_base_of_v<Object, T>, " T must be derived from Object" );
832- static_assert (std::is_same_v<std::decay_t <T>, typename T::self_type>, " T must use GDCLASS or GDSOFTCLASS" );
833- return p_object && p_object->is_class_ptr (T::get_class_ptr_static ()) ? static_cast <const T *>(p_object) : nullptr ;
833+ return p_object && p_object->derives_from <T>() ? static_cast <const T *>(p_object) : nullptr ;
834834 }
835835
836836 enum {
@@ -864,7 +864,8 @@ class Object {
864864 }
865865 virtual bool is_class_ptr (void *p_ptr) const { return get_class_ptr_static () == p_ptr; }
866866
867- bool has_ancestry (AncestralClass p_class) const { return _ancestry & (uint32_t )p_class; }
867+ template <typename T>
868+ bool derives_from () const ;
868869
869870 const StringName &get_class_name () const ;
870871
@@ -1024,7 +1025,7 @@ class Object {
10241025
10251026 void clear_internal_resource_paths ();
10261027
1027- _ALWAYS_INLINE_ bool is_ref_counted () const { return has_ancestry (AncestralClass::REF_COUNTED); }
1028+ _ALWAYS_INLINE_ bool is_ref_counted () const { return _has_ancestry (AncestralClass::REF_COUNTED); }
10281029
10291030 void cancel_free ();
10301031
@@ -1035,6 +1036,29 @@ class Object {
10351036bool predelete_handler (Object *p_object);
10361037void postinitialize_handler (Object *p_object);
10371038
1039+ template <typename T>
1040+ bool Object::derives_from () const {
1041+ static_assert (std::is_base_of_v<Object, T>, " T must be derived from Object." );
1042+ static_assert (std::is_same_v<std::decay_t <T>, typename T::self_type>, " T must use GDCLASS or GDSOFTCLASS." );
1043+
1044+ // If there is an explicitly set ancestral class on the type, we can use that.
1045+ if constexpr (T::static_ancestral_class != T::super_type::static_ancestral_class) {
1046+ return _has_ancestry (T::static_ancestral_class);
1047+ } else {
1048+ return is_class_ptr (T::get_class_ptr_static ());
1049+ }
1050+ }
1051+
1052+ template <>
1053+ inline bool Object::derives_from<Object>() const {
1054+ return true ;
1055+ }
1056+
1057+ template <>
1058+ inline bool Object::derives_from<const Object>() const {
1059+ return true ;
1060+ }
1061+
10381062class ObjectDB {
10391063// This needs to add up to 63, 1 bit is for reference.
10401064#define OBJECTDB_VALIDATOR_BITS 39
0 commit comments