WWW-www.enlightenment.org pushed a commit to branch master. http://git.enlightenment.org/website/www-content.git/commit/?id=c1b10a65081c542981a62ea2fd68c633d247ff8e
commit c1b10a65081c542981a62ea2fd68c633d247ff8e Author: Nate Drake <[email protected]> Date: Tue Nov 21 07:09:02 2017 -0800 Wiki page eo-inherit.md changed with summary [] by Nate Drake --- pages/develop/tutorial/c/eo-inherit.md.txt | 57 +++++++++++++++--------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/pages/develop/tutorial/c/eo-inherit.md.txt b/pages/develop/tutorial/c/eo-inherit.md.txt index df83932e..987cb49b 100644 --- a/pages/develop/tutorial/c/eo-inherit.md.txt +++ b/pages/develop/tutorial/c/eo-inherit.md.txt @@ -12,11 +12,11 @@ This tutorial shows how to inherit from a class in Eolian. It also describes how ## Prerequisites ## * This tutorial builds on top of the ``Example.Rectangle`` class developed in [Creating New Classes with Eolian](eo-classes.md). -* The [Hello World](hello-world.md) tutorial explains how to write an application using the EFL. +* The [Hello World](hello-world.md) tutorial explains how to write an application using EFL. ## Step One: Creating a Derived Class ## -Copy all the ``example_rectangle.*`` files you created in the [Creating New Classes with Eolian](eo-classes.md) tutorial. There should be 4 of them: The Eolian file (``.eo``), the implementation file (``.c``) and two autogenerated files (``.eo.h`` and ``.eo.c``). Also copy the main file (``eo_classes_main.c``) and rename it to ``eo_inherit_main.c``, for consistency with the name of this tutorial. +Copy all the ``example_rectangle.*`` files you created in the [Creating New Classes with Eolian](eo-classes.md) tutorial. There should be 4 of them: The Eolian file (``.eo``), the implementation file (``.c``) and two autogenerated files (``.eo.h`` and ``.eo.c``). Make sure to copy the main file (``eo_classes_main.c``) and rename it to ``eo_inherit_main.c`` for consistency with the name of this tutorial. Now you will create a new class, named ``Example.Square`` which will inherit from ``Example.rectangle``. The theory states that squares are a particular kind of rectangles in which the width and the height are equal. Therefore, the ``Example.Square`` class will *override* ``Example.Rectangle``'s ``width`` and ``height`` setters to ensure that those two variables have always the same value. @@ -31,11 +31,11 @@ class Example.Square (Example.Rectangle) { } ``` -As you can see, it is derived from ``Example.Rectangle``. Regular classes must derive from the ``Efl.Object``, but in this case, you get that automatically, since ``Example.Rectangle`` already derives from ``Efl.Object``. +As you can see this is derived from ``Example.Rectangle``. Regular classes must be derived from ``Efl.Object`` but in this case you get that automatically, since ``Example.Rectangle`` already is already derived from ``Efl.Object``. -You can also notice that this class does not provide any new method or property (there is no ``methods`` block). It only implements two properties, which currently belong to its parent class (``Example.Rectangle.width`` and ``Example.Rectangle.height``). Furthermore, only the setters for these properties are implemented: Reads of these properties will be routed to the getter in the parent class. +You can also notice that this class does not provide any new method or property (there is no ``methods`` block). It only implements two properties, which currently belong to its parent class (``Example.Rectangle.width`` and ``Example.Rectangle.height``). Furthermore only the setters for these properties are implemented: Reads of these properties will be routed to the getter in the parent class. -Next, turn the Eolian description into C files with the ``eolian_gen`` command (as seen in the previous tutorial). Be careful, though, there is a new parameter in use in this example: +Next turn the Eolian description into C files with the ``eolian_gen`` command (as seen in the previous tutorial). Be careful, as there's a new parameter in use in this example: ```bash eolian_gen -gchi example_square.eo -I . @@ -43,13 +43,13 @@ eolian_gen -gchi example_square.eo -I . The ``-I`` parameter tells ``eolian_gen`` where to look for other Eolian files, in case it needs the description of a class it does not know about. In this tutorial, ``Example.Square`` needs the description of ``Example.Rectangle`` which resides in the ``example_rectangle.eo`` file. This file is in the same folder as ``example_square.eo``, the current folder, therefore, the final command requires a ``-I .`` (The dot indicates the current folder). -This will create the boilerplate files (``.eo.h`` and ``.eo.c``) and the implementation file which you will fill in the next step. +This will create the boilerplate files (``.eo.h`` and ``.eo.c``) and the implementation file, which you will complete in the next step. ## Step Two: Implementing the Derived Class ## Edit the implementation file ``example_square.c``. It should contain: -* An empty structure ``Example_Square_Data``. It will remain empty, because squares do not add any additional data to rectangles. +* An empty structure ``Example_Square_Data``. This will remain empty, because squares do not add any additional data to rectangles. * A method called ``_example_square_example_rectangle_width_set()``. This is the setter for the ``width`` property, inherited from the parent ``Example.Rectangle`` class. The name of the method contains all the ancestry information. Don't worry, though, you will not be calling this method directly. * A method called ``_example_square_example_rectangle_height_set()``. As above, this is the setter for the ``height`` property. @@ -59,9 +59,9 @@ The implementation of these methods requires calling the parent class, therefore #include "example_rectangle.eo.h" ``` -Time to think now about the implementation of these setters. They both need to set the ``width`` and ``height`` internal variables to the same value. But these variables are private to ``Example.Rectangle``, so ``Example.Square`` has no direct access to them. They can be accessed through the setters from ``Example.Rectangle``, though. Only care has to be taken not to end up calling the setter from ``Example.Square`` currently being implemented, or an infinite loop would be created. +You now need to focus on implementating these setters. They both need to set the ``width`` and ``height`` internal variables to the same value. These variables are private to ``Example.Rectangle``, so ``Example.Square`` has no direct access to them. These can be accessed through the setters from ``Example.Rectangle`` however. The setter has not been called from the ``Example.Square`` currently being implemented, as this would create an infinite loop. -In EFL, when you need to call a method from your parent instead of your overridden version, you can use ``efl_super()``. Its first parameter is the object and the second is *the class whose parent you want to call*. Write these implementations for the setters and it all will become apparent: +In EFL when you need to call a method from your parent instead of your overridden version you can use ``efl_super()``. Its first parameter is the object and the second is *the class whose parent you want to call*. Write these implementations for the setters and all will become clear: ```c EOLIAN static void @@ -79,16 +79,16 @@ _example_square_example_rectangle_height_set(Eo *obj, Example_Square_Data *pd EI } ``` -Things worth noticing: +Note: * The ``width`` and ``height`` variables are set through the regular setters you already used in the previous tutorial (``example_rectangle_width_set()`` and ``example_rectangle_height_set()``). * The object being passed to the setters, though, is the output of ``efl_super()``. * You want to call the parent of ``Example.Square``, so the second parameter to ``efl_supper()`` is ``EXAMPLE_SQUARE_CLASS``. * These setters do not use the ``Example_Square_Data`` private data (that structure is actually empty, as seen above), so ``EINA_UNUSED`` is used to avoid compiler warnings. -The ``efl_super()`` method can also be used to access older ancestors of your class, but that's an advanced scenario not required in this tutorial. +The ``efl_super()`` method can also be used to access older ancestors of your class but this is a complex operation and so is outside the scope of this tutorial. -Having written these setters, your derived ``Example.Square`` class is finished. The next step adds code that uses it. +Having written these setters your derived ``Example.Square`` class is complete. The next step adds code that uses it. ## Step Three: Using the Derived Class ## @@ -114,15 +114,15 @@ _square_create() } ``` -Observe how the side of the rectangle is set with ``example_rectangle_width_set()``. You could also set the ``height``, since both setters have the same effect on a square. +Note how the side of the rectangle is set with ``example_rectangle_width_set()``. You could also set the ``height`` since both setters have the same effect on a square. -Back in the main function, declare a variable to hold your new object: +Back in the main function declare a variable to hold your new object: ```c Eo *rectangle, *square; ``` -Now call ``_square_create()`` and print some information (right after doing the same thing for the rectangle object): +Next call ``_square_create()`` and print some information, immediately after doing the same thing for the rectangle object: ```c square = _square_create(); @@ -135,9 +135,9 @@ Now call ``_square_create()`` and print some information (right after doing the efl_unref(square); ``` -Notice how you only used ``Example.Rectangle`` methods here, because ``Example.Square`` inherits from it, and all methods that work on a rectangle also work on a square. +Notice how you only used ``Example.Rectangle`` methods here because ``Example.Square`` inherits from it. All methods that work on a rectangle also work on a square. -Also, remember to dispose of your objects using ``efl_unref()`` if you do not give them a parent in ``efl_add()``. +Remember to dispose of your objects using ``efl_unref()`` if you do not give them a parent in ``efl_add()``. The main program (``eo_inherit_main.c``) should now look like this: @@ -203,7 +203,7 @@ efl_main(void *data EINA_UNUSED, const Efl_Event *ev EINA_UNUSED) EFL_MAIN() ``` -If you run it, you should get this on your terminal: +If you run now, you should see this in your terminal: ```bash Rectangle is 5x10, area is 50 @@ -212,9 +212,9 @@ Square is 7x7, area is 49 ## Step Four: Accessing the Parent's Private Data ## -The above implementation for ``Example.Square``'s setters works because ``Example.Rectangle`` has public setters. That is, even though ``width`` and ``height`` are private variables visible only to ``Example.Rectangle`` they can be accessed by anyone through their setters and getters. +The above implementation for ``Example.Square``'s setters works because ``Example.Rectangle`` has public setters. That is to say, even though ``width`` and ``height`` are private variables visible only to ``Example.Rectangle``, they can be accessed by anyone through their setters and getters. -The last step in this tutorial shows how a derived class can access private data from its parent, which is also a common operation in OOP. +The final step in this tutorial shows you how a derived class can access private data from its parent, which is also a common operation in OOP. The first thing done in the implementation file ``example_rectangle.c`` is to define the ``Example_Rectangle_Data`` structure, which is therefore only accessible from that file. If ``Example.Square`` has to have access to this structure, it has to be defined in a common header. @@ -233,7 +233,7 @@ In ``example_rectangle.c``, replace the structure with an include : #include "example_rectangle_private.h" ``` -Finally include the header *also* from ``example_square.c``. At this point, the implementation for ``Example.Square`` can understand the private data of its parent ``Example.Rectangle``. You only need to retrieve a pointer to that data, using ``efl_data_scope_get()``. This is how your square setters should look now: +Finally include the header from ``example_square.c`` too. At this point the implementation for ``Example.Square`` can interpret its parent's private data ``Example.Rectangle``. You only need to retrieve a pointer to that data using ``efl_data_scope_get()``. This is how your square setters should look now: ```c EOLIAN static void @@ -247,24 +247,25 @@ _example_square_example_rectangle_width_set(Eo *obj, Example_Square_Data *pd EIN And likewise for the ``height`` setter. -Notice how the first parameter to ``efl_data_scope_get()`` is the object for which you want to retrieve the private data, and the second parameter is the *ancestor class*. You can retrieve the private data for any class, as long as it belongs to your hierarchy. +Note how the first parameter to ``efl_data_scope_get()`` is the object for which you want to retrieve the private data, and the second parameter is the *ancestor class*. You can retrieve the private data for any class, as long as it belongs to your hierarchy. -> **NOTE:** -> For performance reasons, no runtime check is performed to ensure that the requested class actually belongs to your ancestry. If you want to avoid *undefined behavior* use ``efl_data_scope_safe_get()``. +**NOTE:** + +For performance reasons, no runtime check is performed to ensure that the requested class actually belongs to your ancestry. If you want to avoid *undefined behavior* use ``efl_data_scope_safe_get()``. Once you have the pointer to the private data of ``Example.Rectangle`` you can write to both ``width`` and ``height`` as you were doing before. -Finally, if you need to keep this private data pointer alive for a long time, it is worth reading about ``efl_data_ref()`` and ``efl_data_unref()``. These methods will make sure that the enclosing object is not destroyed until you are done working with its private data. +If you need to keep the private data pointer alive for a long time look into ``efl_data_ref()`` and ``efl_data_unref()``. These methods will make sure that the enclosing object is not destroyed until you are done working with its private data. ## Step Five: Per-Object Method Override ## -One final function worth knowing is ``efl_object_override()``. It allows changing some method's implementation for a particular object, just like derived classes do, but on a single object. +One final function worth knowing is ``efl_object_override()``. It allows changing some method's implementation for a particular object just as derived classes do but on a single object. -Its use case is a bit advanced so it will not be shown in this tutorial. It is related to class inheritance, though, so it deserves being mentioned. +Its use case is a bit advanced so it will not be shown in this tutorial. It is related to class inheritance however so is worthy of note. ## Summary ## -This tutorial has taught you: +In this tutorial, you've learned: * **Derived classes** can be created with Eolian. * **Methods overridden by the derived class** are automatically called when a derived class object is used. --
