Welcome to the Modern Embedded Systems Programming course. My name is Miro Samek and in this lesson I continue the subject of Object- Oriented Programming. Today you will learn about the concept of class *inheritance* and you will see how it works both in C and in C++. As usual, let's get started by making a copy of the previous lesson 29 directory and renaming it to lesson 30. Get inside the new lesson 30 directory and double-click on the uVision project "lesson" to open it. To remind you quickly what happened so far, in the last lesson you started to learn about Object-Oriented Programming (OOP) and you have implemented the first fundamental OOP concept of Encapsulation. Encapsulation means that you organize your code into *classes* that package data and functions together. Specifically, you have implemented a Shape class in C (and later in C++), to represent shapes on an LCD display. Later, you created a few instances of this Shape class, which are called *objects*. These objects then where manipulated exclusively by the class operations, which was the whole point of encapsulation. But, in real software for an LCD display, you would need not just nebulous Shapes. You would need concrete Rectangles, Circles and Triangles. Of course, now that you know the concept of a class, you could create a Rectangle class, a Circle class, a Triangle class and so on, from scratch. But as you will do this, you will notice that all of them would contain attributes for their position on the screen and operations to move them around and to determine the distance among them, plus some other attributes and operations. But wait a minute, didn’t you just implement these exact attributes and operations in your Shape class? Could this be somehow reused in your Rectangle, Circle and Triangle classes? The answer is yes, and is known as the fundamental OOP concept called *inheritance*, which is the ability to define new classes based on existing classes in order to reuse the code and organization. This is the main subject of this lesson. So, here is how you go about creating a Rectangle class based on the Shape class in C. You start the same way as you did for the Shape class by adding the rectangle.h header file to your project and placing the usual include guards in it. Then, you create the attribute structure. But instead of starting from scratch, you add the whole Shape instance as the very *first* attribute, which by a naming convention you call “super”. Later you will see in which sense you can think of this “super” attribute as inherited from Shape, but for now you just state it in the comment. Of course, you need to include the shape.h header file with the Shape struct for this to compile. Now, you can add attributes specific to the Rectangle class, such as the width and the height of the rectangle. Finally, you add operations specific to your Rectangle class. In the constructor, you provide parameters for all attributes: the x0 and y0 for x and y inherited from Shape, and w0 and h0 for width and height added in Rectangle. Finally, you can add operations specific to the Rectangle. For example, you can add operation draw(), which will draw the rectangle on the LCD screen. There is no reason why draw() should change the rectangle, so you could add const before the star to the “me” pointer. Similarly, you can add the area() operation, which will calculate and return the area of the rectangle. Again, the area() operation will not change the "me" instance. When it comes to the definition of the Rectangle class, you add a C file rectangle to your project Next, you need to include the rectangle.h header file with the class interface, after which you copy over the prototypes of the class operations. In the constructor, you first call the Shape constructor for the member "super". This takes care of initializing the inherited attributes. Only after this, you initialize the attributes added in the Rectangle class. In the Rectangle area() operation, you simply return the product of with by height promoted to uint32_t. Finally, in the Rectangle draw() operation, which is potentially more complex, you can simply use some commented out pseudocode for drawing vertical and horizontal lines on the LCD. This is good enough for today, because all you really need at this point is the ability to set a breakpoint inside this operation to determine in the debugger that it has been called. So now, to exercise your Rectangle class, you need to: instantiate it, initialize it with a constructor and call the Rectangle operations on it, like draw() and area(). The code builds cleanly, so let’s open it in the debugger. The most interesting thing I would like you to see here is the layout of the Rectangle object in memory. For this, open the memory view and set it to the beginning of your RAM, that is at hex-2 followed by all zeros. Next, run to the Rectangle constructor and step into it. Here, note the "me" pointer value and find it in the memory view. Now, step into the Shape constructor, and note that the "me" pointer value is the same, even though the type of the "me" pointer has changed from Rectangle to Shape. Before continuing, change the memory view to display signed short values, because the attributes of Shape and also of Rectangle are 16- bit integers. Now, as the Shape constructor runs, it fills out the memory at the beginning of the Rectangle structure. When the control returns back to the Rectangle constructor, it fills out the memory after the Shape portion. In the end your memory layout looks as follows. The whole Rectangle structure is aligned with its first member "super". This is not just a coincidence for the Rectangle struct, but rather a rule that is enshrined in the C-language. Here, for example is the International Standard ISO/IEC for the C programming language. In the section about Structure and unition specifiers you can read, that: "A pointer to a structure object, suitably converted, points to its initial member… There may be unnamed padding within a structure object, but not at its beginning" All of this is, of course, a rather complicated way of saying that a pointer to a structure can be always safely cast on the pointer to the initial member of the structure. This has rather important implications for your Rectangle class, because it means that any pointer to Rectangle can be safely passed to a function expecting a pointer to Shape. This means that all operations for Shapes apply to Rectangles as well. For example, you can call the Shape_moveBy() operation on your Rectangle object and you can also call the distanceFrom() operation as well. In this sense, the Rectangle class *inherits* all operations from the Shape class. However, for this to compile in C you need to explicitly cast Rectangle pointers to Shape pointers. But truly object-oriented programming languages, like C++ *know* that such pointer casting, called "upcasting", is always safe, and OOP languages perform upcasting automatically, as you will see in the second part of this lesson. Now you probably wonder where the term "up-casting" is coming from, so it's time to learn a little of terminology and graphical notation. Here is a class diagram, which is drawn in a traditional way with the base class Shape on top and the derived class Rectangle below. From this you can see that casting from the derived class to the base class goes "up", hence the term "up-casting". The inheritance relationship itself is drawn as an arrow with a big triangular end pointing to the base class, which is often the exact opposite what most people initially think. This is because the arrow points in the direction of generalization, that is from a more specialized class, like Rectangle, to a more general class, like Shape. Therefore, inheritance is also alternatively called generalization. The "base class" is alternatively called "superclass" or "parent class". And the "derived class" is alternatively called "subclass" or a "child class". Finally, you should also realize that class inheritance is not limited to only one level. The Rectangle class itslef can be further specialized for example in a FilledRectangle class, for which Rectangle becomes the base class. All of this can lead to whole family trees of increasingly specialized classes. With this bigger picture in mind, let me offer a few guidelines of how to best THINK about class inheritance. First, the term "inheritance" itself as well as terms like "parent class" and "child class" might suggest the family tree analogy. But this is an incorrect analogy and I would discourage that you think about class inheritance that way. As you saw in the Rectangle class emulation in C, every instance of the derived class literally contains the whole instance of the base class, like Rectangle contains Shape at the attribute "super". With classes, this is done in such a way, that any derived instance can be treated AS an instance of the base class. In other words, inheritance establishes the "Is A..." relationship, such that it makes sense to say "a Rectangle IS A Shape". In contrast, the family tree analogy does not work that way. Donald does not contain inside an instance of his parent Mary Anne and it make no sense to say that "Donald IS Mary Ann", or "Donald IS Fred" for that matter. So, which analogy could you use instead? Well, a good analogy that will shape your thinking correctly is the biological classification of living organisms. In the biological CLASS-ification, it makes sense to say, for example, that a House Cat IS A Felis, meaning a cat-like animal. Further, it makes sense to say that a House Cat IS A Carnivore, meaning a predominantly meat-eating animal. And even further and at the same time, it makes sense to say that a House Cat IS A Mammal, meaning animal that feeds their young with milk. Also, the behaviors introduced in the higher level classes make sense to be inherited by the lower-level classes. For example, the Mammal class might introduce the "lactate operation", meaning to secrete milk to feed the young. This operation makes then sense in all subclasses of Mammal, such as Carnivores, Felis, and House Cats. To finish this longish somewhat theoretical digression, I’d like to compare class inheritance to class composition, so that you understand the difference. So, going back to the code, you implemented inheritance by literally embedding an instance of the superclass inside the subclass. This means that the subclass is a *composition* of the superclass plus some added attributes and operations. This points to some similarities between inheritance and composition. And in fact both approaches can accomplish similar goals, but there is an important difference. Inheritance is the “is a...” relationship, which comes about only when you embed the superclass as the very *first* attribute, so that every instance of the subclass can be treated as an instance of the superclass. If you move the superclass instance to a different position, you still have composition, which is the “has a...” relationship, like Rectangle has a Shape. But you can no longer legitimately perform upcasting. Instead, you would have to explicitly reference the component attribute inside the Rectangle class, which would break encapsulation. So, let me undo the changes and close this project as we are done in C for today. In the last segment of this lesson, I’d like to show you how class inheritance is implemented in C++. Just like in the prvious lesson, this will allow you to directly find out how your C emulation of inheritance differs from a truly object-oriented language and how C++ differs from C. So, let’s start with the C++ code from the previous lesson 29, copy it and rename to lesson30-underscore-cpp. Also, go back to the today’s lesson 30 directory, copy the files rectangle-dot-H and rectangle-dot-C, and paste them into the lesson30-underscore-cpp directory. As the last touch, rename the rectangle-dot-c file to rectangle-dot- CPP. Now, you can drop the project “lesson” onto the uVision IDE to open it. After opening, the first thing you need to do is to add rectangle- dot-H and rectangle-dot-CPP to your project. So, let’s open the rectangle-dot-H header file and convert it to C++. You start exactly like in the previous lesson: You replace typedef struct with the keyword “class” followed by the class name. But now comes the new element of inheritance. For this key object- oriented concept, C++ provides a special syntax, which is colon followed by the base class name and the keyword “public” in front. This means in C++ that Rectangle publicly inherits Shape. The other option would be to inherit Shape privately, but private inheritance is an advanced concept that you don’t need to worry about right now. So this is really all that’s new. The rest of the Rectangle class like the private attributes and public operations are very similar to the previous lesson. So, again you adjust the operations by removing the class-name prefix and removing the “me” pointer, remembering to preserve the const before the asterisk at the end of the prototypes. Now, regarding the derived class implementation, the most interesting change is in the constructor. Just like in C, the derived class needs to call the base-class constructor. But again, C++ provides a special syntax for it, which is based on the constructor initializer list introduced in the last lesson. The draw() operation, even though it is just pseudocode at this stage, offers an interesting dilemma, which is direct access to the inherited attributes from Shape, coded in C as super-dot-x and super- dot-y. If you check in the Shape class, these attributes are declared as private, which restricts the access to them to their own class only. In order for derived classes to have access as well, the base class needs to grant the “protected” access to its attributes. This means that derived classes at any level can access such attributes directly, but the attributes are still protected against any public access. Now, in the draw() operation, you can remove the me-super indirection, because C++ allows you to access the inherited attributes directly, as though they were declared in the derived class. Of course, you can also remove the me pointer from all other parameters, because they are now accessed via the implicit this pointer. Finally, you apply the same changes to the area() operation. As you can see the Rectangle implementation in C++ compiles error- and warning-free. The last remaining step is to actually instantiate and use the Rectangle class in the main-dot-cpp file just like you did it in C. For this, it is convenient to open the previous main.c file in the side view for reference. Please note that the C file is not added to the C++ project. So, first, you need to include the rectangle-dot-H header file in your main-dot-CPP. Next, you can statically allocate a Rectangle object in C++, but in C++ you need to immediately initialize the object via a constructor call. Next, you can call the operations introduced directly in the Rectangle class such as draw() and area(), which you modify the same way as before for the Shape class. But now, you can also call the *inherited* operations from Shape. And here, you can remove the explicit upcasting, because the C++ compiler performs upcasting automatically, knowing that upcasting is always safe. The project builds cleanly, so let’s see how the C++ implementation looks inside the CPU. Before starting the debugger, however, let’s set a breakpoint in the Rectangle constructor. Only now you start the debugger. As you can see, the breakpoint is hit right away, which means that C+ + static constructors run even before main as you already learned in the last lesson. The Locals view shows you the “this” pointer, through which you can conveniently see the object’s attributes as consisting of the inherited Shape part followed by attributes added directly to Rectangle. But let’s also setup the memory view to see the exact layout of the Rectangle object in raw memory. For this, set the memory view to the beginning of your RAM, that is at hex-2 followed by all zeros. Also, setup the view to show signed short numbers, because that happens to be the size of Shape and Rectangle attributes. Now, step from Rectangle into the Shape constructor, and note that the "this" pointer value is the same, even though the type of the "this" pointer has changed from Rectangle to Shape. As the Shape constructor runs, it fills out the Shape attributes, which are clearly at the beginning of the Rectangle memory. When the control returns back to the Rectangle constructor, it fills out the memory after the Shape portion. In the end your memory layout in C++ looks identically as in your C emulation of inheritance. The whole Rectangle object is aligned with the inherited Shape object, which is at the beginning of the Rectangle memory. Now, let’s step over the Shape class operations from the last lesson, and step into the Rectangle operations, such as Rectangle::draw(). Here, like in the Rectangle constructor, you can use the Locals view to very conveniently examine the Rectangle object through the “this” pointer. Same goes for the Rectangle::area() operation. But now come the operations inherited from Shape, like Shape::moveBy(). As you can see in the Locals view, the “this” pointer still points to Rectangle r1, but is automatically upcast to the Shape type and only the Shape portion is now visible in the Locals view. The moveBy() operation changes the Shape attributes, which you can see in both views: Locals and raw memory. Finally, the same upcasting of the “this” pointer happens for the distanceFrom() operation inherited from Shape. This concludes this quick introduction to the Object-Oriented concept of *inheritance*. Today you’ve learned what class inheritance is and how it is a mechanism for reusing common attributes and operations both in C and in C++. But this is not the whole story. Inheritance enables even more reuse as well as extensibility through the third fundamental object- oriented concept of *polymorphism*. This will be the subject of the next lesson. If you like this channel, please give this video a like and subscribe to stay tuned. You can also visit state-machine.com/quickstart for the class notes and project file downloads.