Thursday, July 9, 2009

What is inheritance? Define Public and Private Inheritance. Write an example using C++.?

Taking from OOPS using C++

What is inheritance? Define Public and Private Inheritance. Write an example using C++.?
class Car {


public:


Car();


~Car();


void Accelerate( float howmuch );


void Brake( float howmuch );


int Turn( float howmuch );


int fuel;





private:


int speed;


float accelerate;


int SubFuel(int qty);


};





You should aleady be familiar with the concept of structures (or structs) in C, a structure contains a series of variables which can be used to group data together. A C++ class does much the same thing, except that it not only provides data but also functions to manipulate that data.


Now let's examine this code line by line. The first line simply says 'I want to define a class called 'Car', the syntax is similar to that used in a struct, except that whenever you wanted to create a variable of type Car you only have to type Car mycar; rather than class Car mycar;. The third line declares all the variables that follow to be 'public'. This means that they can be accessed by any piece of code, for example:





void main( void ) {


Car mycar;


int fuel;





mycar.Accelerate( 0.5 ); // Note the use of . to access data members and data functions


fuel = mycar.fuel;// If you had a pointer to a class then you would use -%26gt;, as in a struct


}





Now the forth line is important, it defines a function called 'Car' with no return type. Because this function has the same name as the class it is treated specially, it is called a constructor because whenever a new version of the class is created the constructor is called to initalise the objects data. The fith line is the opposite, because it is the calss name preceded by a ~ symbol it is called the destructor and is automatically called whenever an object is deleted or removed from memory.


The next three lines define three member functions, which can be accessed using the '.' method, these have no special meaning and have to be called manually from code (for example on the sixth line of the 'main' example above accelerate is called for the object 'mycar' of type 'Car'). The nineth line declares a meber variable of type int called fuel, this can be treated in much the same way as you treat a struct's member variable.


The tenth line is another improtant one, it tells the compiler that the member functions and variables that follow it ar private, meaning that they can only be accessed by the member functions of the class. In this case only the functions Car, ~Car, Accelerate, Brake, Turn and SubFuel would be able to access 'speed' or 'accelerate'. This is also true of the private member function 'SubFuel'. Finally two variables called speed and accelerate and a function calle SubFuel are defined.





You have seen that a class can contain member variables that can be public or private depending on who you want to be able to access these functions. It is in fact comon to make all member variables private and use functions to Set and Get them because this has the added advantage of enableing you to 'validate' the new data. In addition to public and private data there is also protected data. Protected data is only accessable by the class itself, derivates (see below) of the class and friends of the class. For example, if you had another calss called Driver and you wanted him to be able to access speed then inserting the following code instead of the private block would give driver access to it:





protected:


int speed;


friend Driver; // make the class 'Driver' a friend, you can also make functions friends


private:


float accelerate;


SubFuel(int qty);





So far you have only seen the declaration of the class, you have not seen the implementation of any of the functions. There are two ways to implement the functions, the first is directly into the class - this method is often used if the function is very short:





// A simplified version of the Car class, demonstarting the simple implementation of the Car constructor


class Car


{


public:


Car() {


fuel = 100;


}


private:


int fuel;


}





The second way which is more common for longer functions is to have the class definition in a header (.h) file so that it can be #included in other files to give them access to the class and to hvae the function implementation in a separate cpp file:





// Implementation of the Car class





// Notice how the 'scope resolution operator ::' is used to say that this function is a member of Car


Car::Car( )


{


fuel = 100;


}





Car::~Car() {


// free any allocated memory here


}





void Car::Accelerate( float howmuch ) {


accelerate += howmuch;


}





int SubFuel( int qty ) {


fuel -= qty;


// return new value;


return fuel;


}





Now you have seen the basics of defiening and implementing a class we will move onto the more advanced topics of inheritence and virtual functions.





So what's all this inheritence stuff then you ask, well, it's one of the most useful features of the C++ langauge. It allows you to take on class (such as our Car class above) and derive a totally new class such as Ferrari, obviously a Ferrari is still a Car, so it inherits the main features of the car - an engine, wheels etc. - but it also adds new features such as cool bodywork and a high top speed. In fact we could then derive another class from Ferrari to specify even more, for example we could have the Ferrari355 or Ferrari550 classes to represent two more specific Ferrari models (the 355 and the 550). Let's take a look at how our class 'Ferrari' might be derived from the Car class:





// #include includes the HEADER file which includes the definition of the 'Car' class.


// in order to be able to derive a class from Car we need to make sure that the Car class


// has been defined so that the compiler knows what a 'Car' is





#include car.h





class Ferrari : public Car {


public:


Ferrari();


Ferrari( int model )





BOOL cool_body_work;


void Accelerate( float howmuch );


};





This code show several new features of C++. The first is the derivation of a class, first we define the class and it's name, then a semi colon is used to separate it from it's base class. The work public which appears before 'Car' describes how to inherit the public members of the Car class, fro example, if you look at the fuel variable in car you will see that it is public, because public appears before Car fuel remains a public variable, but if the key word had been protected or private the status of the 'fuel' variable would have been changed.


Now look at the first constructor of Ferrari, because this has no parameters this is called th default constructor. If you just create the class like you would an integer then this constructor is the one which is called, it is also worth noteing that the constructor for the base class is called first, so the only initalisation you have to worry about in the Ferrari class is taht of the member variables you have added because all the variables in the Car class are initalised by the Car class' constructor.


Now look at the second construcutor, note that it has a parameter. This is how C++ knows which constructor to use, because if you create a Ferrari with the following code:





void main( void ) {


Ferrari mycar( 355 );


mycar.Accelerate( 1.5 );


mycar.Brake( 0.5 );


}





it uses the constructor with one parameter which is an integer. This second constructor has been added to the Ferrari class, and so cannot be used in the car class, in addition the base class's default constructor is also called, even if it did contain a constructor which took one integer as a parameter. If Car contained a similar constructor and you wanted the second constructor for the Ferrari class to use that one instead you would have to use the following code when defining the constrcutor:





Ferrari( int model ) : Car( model );





This simply tells C++ to call the base constructor in Car and pass 'model' as the parameter. Next you will notice that the Ferrai class defines a new variable of the type BOOL (BOOL is commonly used in the Half-Life code. It is a custom variable accepting values of true or false). The variable cool_body_work would most likely be set to true in the constructor for Ferrari. Finally you will see that a function called accelerate has been added. Why? you ask, well, this is because (obviously) Ferraris go faster than normal cars and so we want to override 'Cars' Accelerate function to allow the car to accelerate much faster. It is worth noteing that all public and protected members of Car are still accessable to Ferrari (as can be seen in the example above where the Brake(int) function is called even though mycar is of class Ferrari and Brake is not defined in the definition for Ferrari).


When you are defining the new or overridden members of Ferrari they are defined as above in Car. You do not have to redifine any of the functions in car, except, in theis case Accelerate because it is included in the class definition for Ferrari.





I should put a brief note in here about multiple 'parents' or base classes. You can derive a new class from more than one class as follows, execpt that you will not be able to use 'virtual' functions as described below. This code shows how to derive a class from multiple parents, inheriting the functionality of both (Alpha and Beta need to be defined first for this to work).





// define classes Alpha and Beta


#include "alpha.h"


#include "beta.h"





// Derive class Gamma from Alpha and Beta


class Gamma : public Alpha, Beta {


int greek;


}





Now that we have learnt about deriveing new classes, we are going to have to learn about 'virtual' and 'pure virtual' functions. and about pointers to classes.


Imagine you have a pointer to the class Car, under C++ this pointer can also point to the class Ferrari because Ferrari is derived from Car and so shares all the same members. Now suppose that you called the function 'Accelerate' on this pointer, which version of the 'Accelerate' function would be called? You have a pointer to a Car, but it *really* points to a Ferrari! In this case the function for Car would be called, because the compiler sees a pointer to a Car's Accelerate function, and thinks that means I go off and get the code to accelerate a car - not a ferrari! This is where virtual functions come in. In order to allow you to call the correct function when a pointer to a class is used you have to define the function as virtual, look at the new version of our Car class:





class Car {


public:


Car();


~Car();


virtual void Accelerate( float howmuch );


void Brake( float howmuch );


int Turn( float howmuch );


int fuel;


private:


int speed;


float accelerate;


int SubFuel(int qty);


};





Notice the use of the 'virtual' keyword in front of the Accelerate function. This simply tells the compiler that this is a 'special' function that needs to be called for the derived class (is present) when using pointers. We don't, however, have to define Accelerate as virtual in the Ferrari class unless we want to be able to override accelerate again. With the use of the virtual keyword the correct version of accelerate would be called in the example above. So why aren't all functions virtual? you cry, well, this is to do with performance and accessability. Virtual functions slow down processing time slightly and take up more memory than normal functions, so to provide flexibility without losing performance the virtual keyword must be used.


So what about 'pure virtual' function then. Pure virtual functions are special kinds of functions. They are defined much as in the example above, except that the keyword pure virtual would be inserted before Accelerate instead of just virtual. A pure virtual function is present in the class definition but not defined anyware. This is because classes containing pure virtual functions can never be used, only derived from allowing you to derive several classes from one key object but still point to them all with on class type. Unlike normal functions pure virtual functions MUST be defined in derived classes so that they can be used.





A quick little bit about the scope resolution operator here, '::'. '::' is used in severl circumstances, mainly to access external variables or functions from member classes, or to call base class member functions. In the following example, the implementaiton of Ferrari's Accelerate function calls it's base class and accesses a global variable called fuel.





Ferrari::Accelerate( float howmuch ) {


// ::fuel is a global variable called fuel


// fuel is the member variable of the ferrari class


if(::fuel %26gt;= fuel)


{


// This calls the implementation of Accelerate in our base class Car


Car::Accelerate( howmuch * 4.0f ); // the f makes it a float!


}


}





A quick little bit about the this pointer. The 'this' pointer can be used to pass a pointer to the current class from within one of it's member functions. Suppose you had a class called Epsilon and a global function called SetEpsilon which takes one parameter which is a pointer to an object of type Epsilon. Now, you want to constructor of Epsilon to call the SetEpsilon function to initalise it. The constructor to do this would look something like this:





Epsilon::Epsilon() {


// The this keyword causes a pointer to 'this' class to be passed!


SetEpsilon( this );





// This is pointless, but if Epsilon had a member variable 'int Sigma' then you could access like this


this-%26gt;Sigma = 0;


// But it's much easier just to say


Sigma = 0;


}





So you think you know it all now? Well, not quite. The final thing you really need to know about is the new methods for memory allocation in C++. When using C you may have used the malloc() and free() functions. Whilst these can still be used, and, indeed maybe used for allocating specific amounts of memory, C++ introduces two new operators - the new and delete operators. The new and delete can be used to free and allocate memory, for example:





Ferrari *mynewcar = NULL; // NULL is a #defined value meaning 0





mynewcar = new Ferrari( 355 ); // A 355 Spider!





Notice how a pointer is initalised with the address of the new memory, and that any constructor can be used as before. Of course it is very important that you free any memory allocated with new using the delete operator:





if(mynewcar != NULL %26amp;%26amp; mynewcar-%26gt;crashed()) {


delete mynewcar;


mynewcar = NULL;


}





Notice the use of the -%26gt; operator for a pointer to a class and that I check that the pointer was initalised before using it. Also note that crashed() is a function not present in the examples above, but I though it was appropriate. If you wanted to use 'crashed()' you would have to define and implement it.





Right that's about it for the basics of C++. If there are any experianced C++ readers out there who notice anything significant that I've missed, please mail me so that I can add it! It's best to learn C++ by actually trying some of it, the source code to a C++ version of 'Hello World' is below so that you can try it out and compile your first C++ program!





// Hello World!


// hworld.cpp


#include %26lt;math.h%26gt;


#include %26lt;string.h%26gt;


#include %26lt;stdio.h%26gt;





class hworld {


public:


hworld();


void printmessage( void );


char *getmessage( void );


void setmessage( char *msg );


private:


char *m_message; // convention is for member variables to start with a m_


}





hworld::hworld() {


// initalise the output message


// okay so this is a pretty useless class, but it's a simple example okay!


message = "Hello World!";


}





void hworld::printmessage( void ) {


printf(m_message);


}





char *hworld::getmessage( void ) {


return m_message;


}





void setmessage( char *msg ) {


// check the msg is valid


if(msg != NULL)


message = msg;


// otherwise ignore it!


}





// The main function is the entry point of this application!


void main( void ) {


hworld out;


char *oldmsg;





// store the old message so we can restore it


// no good reason to do this other than to demonstarte it all!


oldmsg = out.getmessage();





// set our own message and send it!


out.setmessage( "Hello World!\n From the hworld class!\n" );


out.printmessage();





// restore the old message (why!)


out.setmessage( oldmsg );


}
Reply://no comment Report It



No comments:

Post a Comment