Inheritance
Created Wednesday 04 May 2016
Concepts learned in CS170:
- Encapsulation
- Hide the inner workings of a class
- Provide an interface to use the class
- An example in C would be "header files". (In them are declarations.)
- double foo(int);
- int goes in, double comes out. We do not care about the implementation.
- Structs in C
1 //Let's say we have a struct: 2 struct Person { 3 char * name; 4 double height, weight; 5 int id; 6 } 7 8 9 struct Person { 10 char * name; 11 double height, weight; 12 int id; 13 } 14 15 //If we didn't have that, this is what we would need: 16 17 void AddPerson (char *, double, double, int); 18 19 //Instead, now we can just do the following: 20 21 void AddPerson (Person const *); 22 23 /* HOWEVER, BECAUSE STRUCTS DO NOT HAVE ACCESS MODIFIERS, 24 THEY ARE NOT ENCAPSULATED.... THEREFORE WE NEED "PUBLIC, PRIVATE, PROTECTED".*/
Inheritance:
- Why do we need it?
- Code Reuse (?)
- But not really... We already have functions that can allow us to reuse code.
- Is a subconcept of modular design
- Treats objects as basic building blocks
- Compose objects to form bigger objects
- Define some kind of relationship between objects.
- Two kinds of relationships: "has-a" and "is-a".
- Polymorphism -> "process objects differently depending on their data type or class"
- Inheritance -> "is-a"
- Code Reuse (?)
1 /* 2 The following is an example of a "HAS-A" relationship: 3 4 Suppose we are designing a Car object. 5 */ 6 7 class Chassis; 8 class Engine; 9 class Wheel; 10 class SteeringWheel; 11 12 class Car 13 {class SteeringWheel 14 { 15 public: 16 void steer_left(); 17 void steer_right(); 18 } 19 20 /* 21 Here we have some examples of polymorphism in action: 22 */ 23 24 class BombBird 25 { 26 public: 27 void fly() {std::cout<<"Bomb fly\n";} 28 }; 29 30 class FireBird 31 { 32 public: 33 void fly() { std::cout<<"Fire fly\n";} 34 }; 35 36 //The following is some really shit code: 37 38 void MakeAllBirdsFly 39 (std::vector<BombBird> & bombbirds, 40 std::vector<FireBird>& firebirds, 41 std::vector<DefaultBird>& defaultbirds) 42 { 43 //blah blah 44 }
- Inheritance
- Describes a "is-a" relationship between two classes.
- The class you inherit from is the Base class
- The inheriting class is the Derived class
- Syntax:
1 class B {...}; 2 class D1: public B {..}; //Everyone knows that you are the son of your father 3 class D2: protected B{...}; //Only people who inherit from you know that you are the son of your father 4 class D3: private B{..}; //Only you know that you are the son of your father, not even your 5 //father knows you're his son 6 //Yes, I am aware that this is a screwed up example. 7 8 class B { public: void foo(); } 9 class D: protected B {} 10 11 D d; 12 d.foo(); //This code is outside B and D. Compile failure. D is not publicly son of B. 13 void D::goo() { D d; d.foo(); } //Ok. 14 15 class B {public: void foo(); } 16 class D: private B {} 17 void D::goo() { this->foo(); } //Ok. 18 19 D d; 20 d.foo(); //This code is outside B and D. Compile failure. D is not publicly son of B 21 void D::goo() {D d; d.foo(); } //Not OK. 22 void D::goo() { this->foo(); } //OK.
- When D inherits from B, we say that D "is a" B.
- IMPORTANT: Classes which inherit from a base class are OUTSIDERS, to a certain extent. Consider the following:
1 class B 2 { 3 public: 4 void foo(); 5 } 6 7 class D2: protected B 8 { 9 void goo(); 10 } 11 12 class D4: public D2 13 { 14 public: 15 void goo(); 16 } 17 18 D4::goo() 19 { 20 D2 d2; 21 D4 d4; 22 d2.foo(); //does NOT work 23 d4.foo(); //works 24 }
IMPORTANT DIRTY TRICK (or why protected is shit):
If you have something that is protected in a previous descendant, you can use something like
1 public: 2 using GrandParent::onlyformychildren;
And it will be public. This is because the using namespace is under public, and you can think of it as "casting" (kinda) the protected variable as a publicly accessible variable... This is why protected is almost never used in professional environments. This can be done to cast to private or protected as well. Many ways to die.
Note that if you wanna do this for functions, leave out the parentheses (brackets).
Hiding
Let's say a descendant has a function called nihao(int), and the descendant before that has nihao(), if you were to call child.nihao() it would NOT execute the grandparent's nihao().... instead, it will find the first available one and complain if it doesn't work.
You can fix this by doing child.GrandParent::nihao(), but that's obviously pretty ugly. You can also use the "using" trick (shown above).
An example is shown below:
1 #include <iostream> 2 3 class GrandParent 4 { 5 public: 6 void nihao() {std::cout<<"GP\n";} 7 }; 8 9 class Parent:public GrandParent 10 { 11 public: 12 void nihao(int x) { std::cout<<"Parent\n";} 13 }; 14 15 class Child:public Parent 16 { 17 public: 18 }; 19 20 int main(void) 21 { 22 Child c; 23 //c.nihao(); // Does not work 24 c.nihao(3); // Works, prints "Parent" 25 c.GrandParent::nihao(); //Works, prints "GP" 26 return 0; 27 }
And a separate example, utilizing the "using" trick:
1 #include <iostream> 2 3 class GrandParent 4 { 5 public: 6 void nihao() {std::cout<<"GP\n";} 7 }; 8 9 class Parent:public GrandParent 10 { 11 public: 12 using GrandParent::nihao; 13 void nihao(int x) { std::cout<<"Parent\n";} 14 }; 15 16 class Child:public Parent 17 { 18 public: 19 }; 20 21 int main(void) 22 { 23 Child c; 24 c.nihao(); // Works now, prints "GP" 25 return 0; 26 }
In private inheritance, classes can be made from within the class to be used as the parent class, but that's it.
Virtual Functions
Virtual stuff, whether it be for classes or functions, is all done at run-time.
Remember, default copy constructor and copy assignment are shallow copies.
When you do most operators, it is almost always necessary to call the base class' function.
Remember, to utilize the base's copy constructor:
1 D2(D2 const & rhs) : B(rhs)
Remember, copy assignments have to be exception-safe.
What does this mean? It means that if you "new" something, and an exception is thrown, you have to handle it properly and the data in the original class must remain intact.
The following example illustrates this; Do note that tmp_buf is a C-Style string:
1 D2& operator=(D2 const & rhs) 2 { 3 char *tmp_buf = new char[rhs.mLen]; 4 std::copy(rhs.buf,rhs.buf + rhs.mLen, tmp_buf); 5 B::operator=(rhs); 6 mLen = rhs.mLen; 7 delete [] buf; 8 buf = tmp_buf; 9 return *this; 10 }
Upcasts and Downcasts
1 //B derives from D. 2 3 D d; 4 B b; 5 b=d; 6 7 //A downcast 8 D d; 9 B b; 10 d=b; 11 12 D d; 13 B b; 14 B& rb = d; //ok 15 B* pb = *d; //ok
1 PolarBear pb; 2 Bear& rb = pb; 3 rb.roar(); //Calls Bear's roar not PolarBear's 4 //This is because roar is calculated at run-time not compile-time
Override
override is a keyword that forces the class to create an error whenever a function is not a virtual.
Multiple Inheritance
The key concept of multiple inheritance is similar to a component-based entity system.
Program to an interface (a class that cannot exist, i.e. an abstract base class (usually done via using virtual functions that are all pure), not to an implementation.
Composition Over Inheritance
It is better to use components (composition/aggregation) instead of inheritance. An example is that if the player wants to have a weapon that can keep on switching. It's super useful.
Definition time:
"Aggregation implies a relationship where the child can exist independently of the parent. Example: Class (parent) and Student (child). Delete the Class and the Students still exist. Composition implies a relationship where the child cannot exist independent of the parent."
Programs should be extremely high-level and abstracted.
Virtual Constructors
Covariant Types
1 #include <iostream> 2 3 class A 4 { 5 public: 6 virtual A * clone() {std::cout<<"Ayy"<<std::endl; return new A(*this);} 7 }; 8 9 class B : public A 10 { 11 public: 12 B * clone() {std::cout<<"Aaaayyyyyy"<<std::endl; return new B(*this);} 13 }; 14 15 int main(void) 16 { 17 A * ab = new B(); 18 ab->clone(); 19 }
The above executes the B code. So you CAN create virtual functions with different signatures but ONLY if the type is a narrowing conversion.
Backlinks: index:CS225 Notes:Topics