浏览代码

Update the Object class engine details page.

Lukas Tenbrink 1 月之前
父节点
当前提交
a2908488d5
共有 1 个文件被更改,包括 138 次插入65 次删除
  1. 138 65
      engine_details/architecture/object_class.rst

+ 138 - 65
engine_details/architecture/object_class.rst

@@ -12,59 +12,73 @@ General definition
 ------------------
 ------------------
 
 
 :ref:`Object <class_object>` is the base class for almost everything. Most classes in Godot
 :ref:`Object <class_object>` is the base class for almost everything. Most classes in Godot
-inherit directly or indirectly from it. Objects provide reflection and
-editable properties, and declaring them is a matter of using a single
+inherit directly or indirectly from it. Declaring them is a matter of using a single
 macro like this:
 macro like this:
 
 
 .. code-block:: cpp
 .. code-block:: cpp
 
 
     class CustomObject : public Object {
     class CustomObject : public Object {
-
-        GDCLASS(CustomObject, Object); // this is required to inherit
+        GDCLASS(CustomObject, Object); // This is required to inherit from Object.
     };
     };
 
 
-This adds a lot of functionality to Objects. For example:
+Objects come with a lot of built-in functionality, like reflection and editable properties:
 
 
 .. code-block:: cpp
 .. code-block:: cpp
 
 
-    obj = memnew(CustomObject);
+    CustomObject *obj = memnew(CustomObject);
     print_line("Object class: ", obj->get_class()); // print object class
     print_line("Object class: ", obj->get_class()); // print object class
 
 
-    obj2 = Object::cast_to<OtherClass>(obj); // converting between classes, this also works without RTTI enabled.
+    OtherClass *obj2 = Object::cast_to<OtherClass>(obj); // Converting between classes, similar to dynamic_cast
 
 
 References:
 References:
 ~~~~~~~~~~~
 ~~~~~~~~~~~
 
 
 -  `core/object/object.h <https://github.com/godotengine/godot/blob/master/core/object/object.h>`__
 -  `core/object/object.h <https://github.com/godotengine/godot/blob/master/core/object/object.h>`__
 
 
-Registering an Object
----------------------
-
-ClassDB is a static class that holds the entire list of registered
-classes that inherit from Object, as well as dynamic bindings to all
-their methods properties and integer constants.
+Registering Object classes
+--------------------------
 
 
-Classes are registered by calling:
+Most ``Object`` subclasses are registered by calling ``GDREGISTER_CLASS``.
 
 
 .. code-block:: cpp
 .. code-block:: cpp
 
 
-    ClassDB::register_class<MyCustomClass>()
+    GDREGISTER_CLASS(MyCustomClass)
 
 
-Registering it will allow the class to be instanced by scripts, code, or
-creating them again when deserializing.
+This will register it as a named, public class in the ``ClassDB``, which will allow the class to be instantiated by
+scripts, code, or by deserialization. Note that classes registered as ``GDREGISTER_CLASS`` should expect to be
+instantiated or freed automatically, for example by the editor or the documentation system.
 
 
-Registering as virtual is the same but it can't be instanced.
+Besides ``GDREGISTER_CLASS``, there are a few other modes of privateness:
 
 
 .. code-block:: cpp
 .. code-block:: cpp
 
 
-    ClassDB::register_virtual_class<MyCustomClass>()
+    // Registers the class publicly, but prevents automatic instantiation through ClassDB.
+    GDREGISTER_VIRTUAL_CLASS(MyCustomClass);
+
+    // Registers the class publicly, but prevents all instantiation through ClassDB.
+    GDREGISTER_ABSTRACT_CLASS(MyCustomClass);
+
+    // Registers the class in ClassDB, but marks it as private,
+    // such that it is not visible to scripts or extensions.
+    // This is the same as not registering the class explicitly at all
+    // - in this case, the class is registered as internal automatically
+    // when it is first constructed.
+    GDREGISTER_INTERNAL_CLASS(MyCustomClass);
+
+    // Registers the class such that it is only available at runtime (but not in the editor).
+    GDREGISTER_RUNTIME_CLASS(MyCustomClass);
+
+It is also possible to use ``GDSOFTCLASS(MyCustomClass, SuperClass)`` instead of ``GDCLASS(MyCustomClass, SuperClass)``.
+Classes defined this way are not registered in the ``ClassDB`` at all. This is sometimes used for platform-specific
+subclasses.
+
+Registering bindings
+~~~~~~~~~~~~~~~~~~~~
 
 
 Object-derived classes can override the static function
 Object-derived classes can override the static function
-``static void _bind_methods()``. When one class is registered, this
+``static void _bind_methods()``. When the class is registered, this
 static function is called to register all the object methods,
 static function is called to register all the object methods,
-properties, constants, etc. It's only called once. If an Object derived
-class is instanced but has not been registered, it will be registered as
-virtual automatically.
+properties, constants, etc. It's only called once.
 
 
 Inside ``_bind_methods``, there are a couple of things that can be done.
 Inside ``_bind_methods``, there are a couple of things that can be done.
 Registering functions is one:
 Registering functions is one:
@@ -95,12 +109,12 @@ documented as thoroughly, the ``D_METHOD()`` macro can safely be ignored and a
 string passing the name can be passed for brevity.
 string passing the name can be passed for brevity.
 
 
 References:
 References:
-~~~~~~~~~~~
+^^^^^^^^^^^
 
 
 -  `core/object/class_db.h <https://github.com/godotengine/godot/blob/master/core/object/class_db.h>`__
 -  `core/object/class_db.h <https://github.com/godotengine/godot/blob/master/core/object/class_db.h>`__
 
 
 Constants
 Constants
----------
+~~~~~~~~~
 
 
 Classes often have enums such as:
 Classes often have enums such as:
 
 
@@ -126,7 +140,7 @@ The constants can also be bound inside ``_bind_methods``, by using:
     BIND_CONSTANT(MODE_SECOND);
     BIND_CONSTANT(MODE_SECOND);
 
 
 Properties (set/get)
 Properties (set/get)
---------------------
+~~~~~~~~~~~~~~~~~~~~
 
 
 Objects export properties, properties are useful for the following:
 Objects export properties, properties are useful for the following:
 
 
@@ -181,7 +195,7 @@ This creates the property using the setter and the getter.
 .. _doc_binding_properties_using_set_get_property_list:
 .. _doc_binding_properties_using_set_get_property_list:
 
 
 Binding properties using ``_set``/``_get``/``_get_property_list``
 Binding properties using ``_set``/``_get``/``_get_property_list``
------------------------------------------------------------------
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 
 An additional method of creating properties exists when more flexibility
 An additional method of creating properties exists when more flexibility
 is desired (i.e. adding or removing properties on context).
 is desired (i.e. adding or removing properties on context).
@@ -201,26 +215,9 @@ call).
 This is also a little less efficient since ``p_property`` must be
 This is also a little less efficient since ``p_property`` must be
 compared against the desired names in serial order.
 compared against the desired names in serial order.
 
 
-Dynamic casting
----------------
-
-Godot provides dynamic casting between Object-derived classes, for
-example:
-
-.. code-block:: cpp
-
-    void somefunc(Object *some_obj) {
-
-         Button *button = Object::cast_to<Button>(some_obj);
-    }
-
-If cast fails, NULL is returned. This system uses RTTI, but it also
-works fine (although a bit slower) when RTTI is disabled. This is useful
-on platforms where a small binary size is ideal, such as HTML5 or
-consoles (with low memory footprint).
 
 
 Signals
 Signals
--------
+~~~~~~~
 
 
 Objects can have a set of signals defined (similar to Delegates in other
 Objects can have a set of signals defined (similar to Delegates in other
 languages). This example shows how to connect to them:
 languages). This example shows how to connect to them:
@@ -244,35 +241,111 @@ Adding signals to a class is done in ``_bind_methods``, using the
 
 
     ADD_SIGNAL(MethodInfo("been_killed"))
     ADD_SIGNAL(MethodInfo("been_killed"))
 
 
-Notifications
--------------
+Object ownership and casting
+----------------------------
 
 
-All objects in Godot have a :ref:`_notification <class_Object_private_method__notification>`
-method that allows it to respond to engine level callbacks that may relate to it.
-More information can be found on the :ref:`doc_godot_notifications` page.
+Objects are allocated on the heap. There are two different ownership models:
 
 
-References
-----------
+- Objects derived from ``RefCounted`` are reference counted.
+- All other objects are manually memory managed.
+
+The ownership models are fundamentally different. Refer to the section for each respectively to learn how to
+create, store, and free the object.
+
+When you do not know whether an object passed to you (via ``Object *``) is ``RefCounted``, and you need to store it,
+you should store its ``ObjectID`` rather than a pointer (as explained below, in the manual memory management section).
 
 
-:ref:`RefCounted <class_RefCounted>` inherits from Object and holds a
-reference count. It is the base for reference counted object types.
-Declaring them must be done using Ref<> template. For example:
+When an object is passed to you via :ref:`Variant<class_Variant>`, especially when using deferred callbacks, it is
+possible that the contained ``Object *`` was already freed by the time your function runs.
+Instead of converting directly to ``Object *``, you should use ``get_validated_object``:
 
 
 .. code-block:: cpp
 .. code-block:: cpp
 
 
-    class MyReference: public RefCounted {
+    void do_something(Variant p_variant) {
+        Object *object = p_variant.get_validated_object();
+        ERR_FAIL_NULL(object);
+    }
+
+Manual memory management
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Manually memory managed objects are created using ``memnew`` and freed using ``memdelete``:
+
+.. code-block:: cpp
+
+    Node *node = memnew(Node);
+    // ...
+    memdelete(node);
+    node = nullptr;
+
+When you are not the sole owner of an object, storing a pointer to it is dangerous: The object may at any point be
+freed through other references to it, causing your pointer to become a dangling pointer, which will eventually result in
+a crash.
+
+When storing objects you are not the only owner of, you should store its ``ObjectID`` rather than a pointer:
+
+.. code-block:: cpp
+
+    Node *node = memnew(Node);
+    ObjectID node_id = node.get_instance_id();
+    // ...
+    Object *maybe_node = ObjectDB::get_instance(node_id);
+    ERR_FAIL_NULL(maybe_node); // The node may have been freed between calls.
+
+``RefCounted`` memory management
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+:ref:`RefCounted <class_RefCounted>` subclasses are memory managed with
+`reference counting semantics <https://en.wikipedia.org/wiki/Reference_counting>`__.
+
+They are constructed using ``memnew``, and should be stored in ``Ref`` instances. When the last ``Ref`` instance is
+dropped, the object automatically self-destructs.
+
+.. code-block:: cpp
+
+    class MyRefCounted: public RefCounted {
         GDCLASS(MyReference, RefCounted);
         GDCLASS(MyReference, RefCounted);
     };
     };
 
 
-    Ref<MyReference> myref(memnew(MyReference));
+    Ref<MyRefCounted> my_ref = memnew(MyRefCounted);
+    // ...
+    // Ref holds shared ownership over the object, so the object
+    // will not be freed. As long as you have a valid, non-null
+    // Ref, it can be safely assumed the object is still valid.
+    my_ref->get_class_name();
 
 
-``myref`` is reference counted. It will be freed when no more Ref<>
-templates point to it.
+You should never call ``memdelete`` for ``RefCounted`` subclasses, because there may be other owners of it.
+
+You should also never store ``RefCounted`` subclasses using raw pointers, for example
+``RefCounted *object = memnew(RefCounted)``. This is unsafe because other owners may destruct the object, leaving you
+with a dangling pointer, which will eventually result in a crash.
 
 
 References:
 References:
-~~~~~~~~~~~
+^^^^^^^^^^^
+
+-  `core/object/ref_counted.h <https://github.com/godotengine/godot/blob/master/core/object/ref_counted.h>`__
+
+Dynamic casting
+~~~~~~~~~~~~~~~
+
+Godot provides dynamic casting between Object-derived classes, for example:
+
+.. code-block:: cpp
+
+    void some_func(Object *p_object) {
+         Button *button = Object::cast_to<Button>(p_object);
+    }
+
+If the cast fails, ``nullptr`` is returned. This works the same as ``dynamic_cast``, but does not use
+`C++ RTTI <https://en.wikipedia.org/wiki/Run-time_type_information>`__.
+
+Notifications
+-------------
+
+All objects in Godot have a :ref:`_notification <class_Object_private_method__notification>`
+method that allows them to respond to engine-level callbacks that may relate to it.
+More information can be found on the :ref:`doc_godot_notifications` page.
 
 
--  `core/object/reference.h <https://github.com/godotengine/godot/blob/master/core/object/ref_counted.h>`__
 
 
 Resources
 Resources
 ----------
 ----------
@@ -291,7 +364,7 @@ References:
 -  `core/io/resource.h <https://github.com/godotengine/godot/blob/master/core/io/resource.h>`__
 -  `core/io/resource.h <https://github.com/godotengine/godot/blob/master/core/io/resource.h>`__
 
 
 Resource loading
 Resource loading
-----------------
+~~~~~~~~~~~~~~~~
 
 
 Resources can be loaded with the ResourceLoader API, like this:
 Resources can be loaded with the ResourceLoader API, like this:
 
 
@@ -307,12 +380,12 @@ the same time.
 -  resourceinteractiveloader (TODO)
 -  resourceinteractiveloader (TODO)
 
 
 References:
 References:
-~~~~~~~~~~~
+^^^^^^^^^^^
 
 
 -  `core/io/resource_loader.h <https://github.com/godotengine/godot/blob/master/core/io/resource_loader.h>`__
 -  `core/io/resource_loader.h <https://github.com/godotengine/godot/blob/master/core/io/resource_loader.h>`__
 
 
 Resource saving
 Resource saving
----------------
+~~~~~~~~~~~~~~~
 
 
 Saving a resource can be done with the resource saver API:
 Saving a resource can be done with the resource saver API:
 
 
@@ -326,6 +399,6 @@ be bundled with the saved resource and assigned sub-IDs, like
 ``res://someresource.res::1``. This also helps to cache them when loaded.
 ``res://someresource.res::1``. This also helps to cache them when loaded.
 
 
 References:
 References:
-~~~~~~~~~~~
+^^^^^^^^^^^
 
 
 -  `core/io/resource_saver.h <https://github.com/godotengine/godot/blob/master/core/io/resource_saver.h>`__
 -  `core/io/resource_saver.h <https://github.com/godotengine/godot/blob/master/core/io/resource_saver.h>`__