Skip to main content
GameDev.net gamedev.net
📌 Pinned 🔒 Locked

C++ Workshop - Inheritance (Ch. 12)

Started by JWalsh Aug 21, 2006 at 12:56 PM 39 replies 35k views
Original Post
JWalsh
JWalsh

Welcome to the GDNet C++ Workshop – Ch. 12

For a complete introduction to this workshop, please look here. Workshop Overview This workshop is designed to aid people in their journey to learn beginning C++. This workshop is targeted at highly motivated individuals who are interested in learning C++ or who have attempted to learn C++ in the past, but found that without sufficient support and mentoring they were unable to connect all the pieces of this highly complex but powerful programming language. This is a 'guided' self-teaching C++ workshop. Each student is responsible for taking the time to read the material and learn the information. The community and tutors that arise out of this workshop are here for making the learning process run more smoothly, but are not obligated to baby-sit a person's progress. Because everyone will be working from the same textbook (Teach Yourself C++ in 21 days 5th Ed.), students may find it easier to get answers to the specific questions they might have. There is no minimum age requirement, and there is no previous programming experience required. Additionally, this workshop does not attempt to defend C++ as a language, nor does it attempt to demonstrate that C++ is either more or less useful then other programming languages for any particular purpose. People who intend to start a discussion about the differences between C++ and ANY other languages (except as are relevant to a particular discussion), are encouraged to do so elsewhere. This workshop is for educational, not philosophical discussions. Quizzes & Exercises Each week will have quizzes and exercises posted in the weekly threads. Please try and answer them by yourself. As well, please DO NOT post the answers to Quizzes and Exercises within this thread. Once it becomes acceptable to post the answers to quizzes and exercises, an additional thread will be created each week specifically for the purpose of posting quiz answers. If you try with reasonable effort but are unable to answer the questions or complete the exercises, feel free to post a clarification question here on the thread. Tutors, myself, or others will do the best we can to point you in the right direction for finding the answer.

Chapter 12 – Implementing Inheritance

Introduction Heya all, Welcome to week 10! This week we'll explore the chapter on Inheritance. This is a fundamental part of all object oriented languages as it is the primary feature which allows code-reuse, while still being able to make subtle changes to your specific implementation. In this chapter we'll look at what Inheritance is, how it's implemented in C++, how to protect data when using inheritance, and we'll be introduced to the virtual function table - a stepping stone to polymorphism. This chapter is approximately 32 pages and will end, as usual, next Sunday. In addition to this week's chapter, make sure you check out Project 1. This project is designed to test everything you've learned so far. Expressions, branching, functions, pointers, classes, loops, and object oriented design. Additionally, it may be required to peek into the chapter on arrays for easier implementation. I'm looking forward to seeing what each person following the tutorial can come up with. If you find you're having technical questions about how to do something, you might want to go back and re-read a chapter or 2. If you're having questions about design, and where to get started, well...welcome to the wonderful world of problem solving. Please feel free to post questions in the Project 1 thread on how to design the program. Please remember to use OPINION and WARNING tags whenever applicable. As well, feel free to post your own insights, and review questions or exercises beginning Wednesday or Thursday. Outline of the Reading - Chapter 12
  1. What is Inheritance?
  2. Private versus Protected
  3. Inheritance with Constructors and Destructors
  4. Overriding Base Class Functions
  5. Virtual Methods

Good Luck!

[Edited by - jwalsh on May 30, 2007 1:02:45 PM]
kingIZZZY
kingIZZZY
[OPINION]
Unless im really out of it, I dont really see why you would need inheritance in Project 1.
[/OPINION]

[Edited by - kingIZZZY on August 22, 2006 11:24:52 PM]
RinusMaximus
RinusMaximus
Quote:
Original post by kingIZZZY
Unless im really out of it, I dont really see why you would need inheritance in Project 1.


I'm not planning on writing each menu from scratch. I want to write one base menu and extend from that one for each menu in the game.

Also, I might make a Character and make the PlayerCharacter and ComputerCharacter extend from that. Although I'm not sure about that last one, those two characters might need the exact same functionality.
Deyja
Deyja
Eh. I wrote it in C. In about two hours. You never need inheritence; it just makes some stuff easier. An 'ooped' design now will probably make the later projects easier, though.

[edit]I should say, you don't need language support for inheritence. Some problems may still require you to mimic that behaviour with other means.[/edit]
JWalsh
JWalsh
Quote:
Original post by Deyja
Eh. I wrote it in C. In about two hours. You never need inheritence; it just makes some stuff easier. An 'ooped' design now will probably make the later projects easier, though.

[edit]I should say, you don't need language support for inheritence. Some problems may still require you to mimic that behaviour with other means.[/edit]


It's important to note that this is a C++ Workshop. I do not encourage anyone to use C to implement anything. If you're using C to implement the projects, you're missing the point.

Also, I'd like to remind people who are attempting to help others to use the [OPINION] tags when you're stating something which may be your opinion, and not empirically proven true.

[Edited by - jwalsh on August 28, 2006 2:36:56 PM]
kingIZZZY
kingIZZZY
Quote:
I'm not planning on writing each menu from scratch. I want to write one base menu and extend from that one for each menu in the game.
[OPINION]
Several questions arise if you think of menus as classes;
1. how will this indeed save you the work of re-typing all different menus and sub-menus? even with inheritance, every menu has its different choice print-out, aswell as different responses to each choice-input by user. How will this (-making a menu an OBJECT) be shorter than making global menu functions?
2. In menus, one function branching to another function makes alot more sense, than one menu object creating another menu object who's inheriting the attributes of a base-menu.
3. A menu is not an object, A menu doesnt need memory allocation for private variables etc. A menu is just a branch of code leading you to other branches of the program you may want to use. An object is something of the real world you would like to simulate, like armor, or weapons, or characters. And these objects are created, used, and destroyed in thier own useful part of the program- their appropiate global function.
[/OPINION]

(p.s. if you just want to use the functionality of a class to make menu-coding shorter, refer to question 1.)
RinusMaximus
RinusMaximus
Quote:
Original post by kingIZZZY
Quote:
I'm not planning on writing each menu from scratch. I want to write one base menu and extend from that one for each menu in the game.
[OPINION]
Several questions arise if you think of menus as classes;
1. how will this indeed save you the work of re-typing all different menus and sub-menus? even with inheritance, every menu has its different choice print-out, aswell as different responses to each choice-input by user. How will this (-making a menu an OBJECT) be shorter than making global menu functions?
2. In menus, one function branching to another function makes alot more sense, than one menu object creating another menu object who's inheriting the attributes of a base-menu.
3. A menu is not an object, A menu doesnt need memory allocation for private variables etc. A menu is just a branch of code leading you to other branches of the program you may want to use. An object is something of the real world you would like to simulate, like armor, or weapons, or characters. And these objects are created, used, and destroyed in thier own useful part of the program- their appropiate global function.
[/OPINION]

(p.s. if you just want to use the functionality of a class to make menu-coding shorter, refer to question 1.)


[OPINION]
1. Of course this will not save me the time of re-writing every option that is displayed on the screen. It will save me the time of writing how to get user input and validating user input. It will also give me the possibility of using each menu in a unified way. I can display any menu in my game in the same way, regardless of which menu it is.

If I would, for example, put my menu's on a stack, I would have a very easy way of opening and closing different menu's on top of each other. Each menu can be programmed separately of any other menu's. I will only have to code the opening and closing of a menu once, where you have to program this for each menu you create. Also, you'll need some extra logic for each menu to see which menu it should return to when it closes.

2. I don't think this makes a lot more sense. If you're adding a new menu the next time you go back to the game, you have to go back to, either your main class or your single menu class and add the menu there. Were I can add a new menu class, which inherits most of it's logic from the menu base class.

My base menu class will probably don't have any attributes. And it will only provide a couple of methods. So whats the sense in creating this base menu? My base menu will be a contract for each menu I create. Regardless of which menu I have I know that for example:
Menu.open(); opens my menu.
Menu.close(); closes my menu.

3. I think this is where we really disagree. Because a menu is not an object you can touch in the real world, like armor or a weapon, it doesn't mean it's not an object.
Also, I think in Object Oriented Programming you should avoid using global functions as much as you can. For each global function you lose all the benefits Object Oriented Programming gives you.
[/OPINION]
Oluseyi
Oluseyi
Quote:
Original post by jwalsh
C is an outdated language, retired by its creators in favor of the easier to use and more powerful C++.

Uh, no.

Quote:
Also, I'd like to remind people who are attempting to help others to use the [OPINION] tags when you're stating something which may be your opinion, and not empirically proven true.

Like the above?
JWalsh
JWalsh
Quote:
Original post by Oluseyi
Quote:
Original post by jwalsh
C is an outdated language, retired by its creators in favor of the easier to use and more powerful C++.

Uh, no.



If you wish to argue the point I suppose we can, but I tend to believe there's far more beneficial ways we could be spending our time.

[OPINION]
Writing new code in C when C++ is an option, or attempting to learn C before C++ is both counter-productive and unnecessary.
[/OPINION]

The formula followed for procedural programming has shown to not only not be helpful, but also detrimental to the learning process of C++.

If you wish to start yet another C vs. C++ discussion, please post it in FB or GP and PM me the link, and we can continue the discussion there. It does not belong here. I was not attempting to start a debate about the choices or uses of languages. I was simply trying to discourage people from using C in a C++ workshop. Which seems only fair.

Cheers!

[Edited by - jwalsh on August 23, 2006 3:35:52 AM]
Zahlman
Zahlman
[OPINION, but based on actually implementing this kind of thing several times for the benefit of random FB forum threads]
Creating an object to represent a menu is likely to be useful. Involving inheritance is not.

Normally, inheritance is invoked to provide differences in behaviour: the general interface of the base class says what classes in the hierarchy can do, and the subclasses implement different *ways of doing that*. But you should first check to see if you can make it work by using the same class and varying the *data that is worked upon*. For example, think of the items of a menu, and the title, as components of the menu. Can you see how you don't need any inheritance to represent different menus? You just put different items into each menu instance. Now apply the same analysis to those components: what can a menu item "do"? How many sensible ways are there to do it?
[/OPINION]
samanime
samanime
[opinion]
I can see how to do this in many different ways.

I could do it via procedural methods, like you would do in C, I can see doing it simply with OO and I can see using inheritence. I think I will do the project in two ways, both simple OO and making good use of inheritence.
[/opion]

Also, regardless whether this specific project makes good use of inheritence or not, you should still learn to make good use of it because it is an invaluable tool.
kingIZZZY
kingIZZZY
what's the difference between what you call "simple OO" vs. inheritance?
samanime
samanime
[opinion]
Simple OO would be to simply treat everything as an object.

So, for example, you could have a class Car.

class Car{private: // member data ...public: //constructors ... //member functons void startEngine(); //turn on the cars engine void accelerate(); //accelerate the car's speed void decelerate(); //slow the car down. void stopEngine(); //turn off the cars engine};


and the Car class would have every member function it needs inside of it.

Now, if you were going to create a variety of wheeled vehicles, you could do this more effectively by created a base class to derive them from and then creating child that have the specifics. So, we could have a WheeledVehicle class and then have a Car class derivated.

class WheeledVehicle{private: // member data ...public: //constructors ... //member functons void accelerate(); //increase the vehicle's speed void decelerate(); //decrease the vehicle's speed};class Car : public WheeledVehicle{private: // member data ...public: //constructors ... //member functons void startEngine(); //turn on the car's engine void stopEngine(); //turn off the car's engine //No need to redefine accelerate() or decelerate() because they are inherited  // from WheeledVehicle.};


Using inheritence, you could create many different types without having to recreate anything. From WheeledVehicle you could also derive Bicycle which would have pedal() and from car you could have classes like SportsCar, SUV, etc.

Basically, you could do it either way, but when you use inheritence, you reuse code the you have already written, which is one of the main purposes of OO, and you can create new classes that share similarities with each other.

There is no need to reinvent the wheel.
[/opinion]

And, I haven't noticed it anywhere yet, so:
[warning]
Be sure that when you declare a child, you have the parent as public.

Example:

class Car : WheeledVehicle
{
//definitions
...
};


will give you an error when you try to call protected member functions or data of WheeledVehicle.

class Car : public WheeledVehicle{ //definitions ...};


will let you use WheeledVehicle's protected member functions or data without problem.
[/warning]

[Edited by - samanime on August 24, 2006 3:52:36 PM]
Deyja
Deyja
[Opinion - of Scott Myers, Author of the Effective C++ series, and of Herb Sutter, Author of the Exceptional C++ series - and also of me.]
When using inheritence, you must understand what the different kinds of inheritence mean.

Public inheritence models an 'is-a' relationship. For example, if Tabby inherits publicly from Cat, then it means that 'Tabby is a Cat'. Not that Tabby is a kind of Cat; and this is the confusing part - knowing the difference between 'is a' and 'is a kind of'. When a function takes a Cat*, that pointer can point to a Cat or to anything derived from Cat. Therefore, if Cat makes certain guarantees about it's state, derived classes must uphold them. From the view of the code using the Cat*, it must not matter in any way wether the pointer points to a Cat or to a Tabby. This is called the Liskov Substitution Principle.
The best example of a violation of this principle that I've yet found is this.
Imagine you have a class 'Rectangle' which has the virtual member funtions 'set_width' and 'set_height'. You derive 'Square' publicly from 'Rectangle' because, of course, a Square 'is a' Rectangle. Unfortunatly, while this may be true in mathmatics, it fails when subjected to the substitution test. When using Rectangles, if you 'set_width', the height remains unchanged, and vice versa. This isn't true for squares. Squares must maintain the additional invariant that the width and height must be the same. Calling set_width on a square must also change the height. Therefore, the class does not satisfy the Liskov Substitution Principle. We come to the conclusion that derived classes can only apply additional invariants when they do not break the invariants imposed by the parent class.

Protected inheritence models an 'is implemented in terms of' relationship, and is the preffered method of inheritence when you are interested in code reuse and there is no other method available, or if you need access to protected members of the class. Remember that only public inheritence allows you to use a derived type as if it were the parent type.

Private inheritence models a 'has a' relationship, and is little different them simple containment. An example -
class Foo {};//private inheritenceclass Bar1 : private Foo {}; //Bar1 'has a' Foo//containmentclass Bar2  //Bar2 also 'has a' Foo{   Foo m_foo; };

Private inheritence differs greatly from Containment in syntax. It unfortunatly has few advantages over Containment. The one most often touted is the 'empty base' optimization. Even if a class is empty, (That is; has no data members and no virtual functions) the compiler must give it atleast one byte of storage. This is because every variable must have a unique address, and if a class took up zero space the next variable declared would have the same address (I am simplifying. All sorts of things could end up at that same address) In some cases, when a class derives from an empty class, the compiler does NOT need to give any space inside the derived class (Bar1 above) to the parent class (Foo above). This is not possible with containment, and it is often not possible with public inheritence either (Depending greatly on how the compiler implements stuff)
[/Opinion]
CondorMan
CondorMan
I've found this chapter fascinating - but have come across something that I don't understand. I realise the use of virtual methods but don't know why destructors (i.e. Listing 12.8, lines 9 & 21 and Listing 12.9, line 9) are also designated as virtual. I removed both virtuals in Listing 12.8 and the console didn't report the dog destructor as having been called.

There must be some logic in having destructors as virtual because I've seen them designated as such in other listings, I just don't know why!
Zahlman
Zahlman
Except for being automatically called at the end of a variable's lifetime, a destructor is just like any other member function. Thus, it needs to be virtual if it will be used polymorphically, i.e. if you will create a pointer to base, point it to a derived class, and then try to deallocate the derived object via the base pointer. If the destructor were not virtual, then the 'delete' call would be forced to use the *static* type of the pointer, i.e. Base*, and invoke that destructor.

See more here.
kingIZZZY
kingIZZZY
c'mon, what happened to the noise, everyone still on vacation or something?
and when is week 11 chapter 13 called for?
CondorMan
CondorMan
There is reference in a couple of places that "nested" derived classes are possible (Mammal, Pet, Dog etc.) but is there a restriction on the number of such nested classes imposed by the language or compiler? I suspect that the answer is no and, if that's the case, any restriction is self-imposed by the programmer in the interest of being able to read and understand the code.

If my assumption is correct, what would folks say is a reasonable maximum number of nested derived classes, for instance when creating a really large and complicated application?

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.