botman's botsHalf-Life bot development |
|
Home/News
About Projects Downloads MOD FAQ Building the SDK - Half-Life SDK - C++ Basics SDK Humor HPB Waypoint files Forum Links
|
Basics on C++ Objects
and Inheritance:
C++ is a superset of the C programming language. C++ is an object-oriented language. This means that C++ allows you to deal with things as though they were real objects (they have specific characteristics or attributes, and they have specific behaviors or methods, which are things that you can do to them). For example, in C++ you could create an object for a door. The door object might have attributes like height, width, color, and material. The door object might have methods (things that you can do to it) like open, close, lock, and unlock. Once the "door object" was created you could use it for many different types of doors. You would know that each one of them would have a height, width, color and material attribute. You would know that you could open, close, lock and unlock each one of them. In C++ you could create a door object by using the following code... enum Color {red, green, blue, black, white};
class Door
int height;
bool Open( void );
Door my_door; In this example "Door" is a class (object) that I have created, and "my_door" is an instance of that object. You can only manipulate instances of objects, you can't do anything with the "Door" object itself. Once I have created the "my_door" instance of the Door object I can do things like this in C++… void main( void )
my_door.height = 60;
// ERROR! The C++ compiler
won't let you do this
if ( my_door.Open() )
if ( my_door.material == wood )
// ERROR! The C++ compiler
won't let you do this!!!
The "public:" keyword in the Door makes the variables (attributes) and functions (methods) publicly accessible so that even code outside the scope of the Door object can get to them. Normally attributes are private which means that only the code belonging to Door can access them. You create code within the scope of an object by using the object name followed by two colons like this Door::. Here's a slightly different Door object with private attributes and public methods… class Door
int height;
public: void SetHeight( int value );
bool Open( void );
I have made the height, width, color and material attributes private so that only the Door object knows about them. Here is how the C++ code from above would have to be modified to work with the new Door object… void Door::SetHeight( int value )
int Door::GetHeight( void )
void Door::SetWidth( int value )
int Door::GetWidth( void )
void Door::SetColor( Color value )
Color Door::GetColor( void )
void Door::SetMaterial( Material value )
Material Door::GetMaterial( void )
void main( void )
my_door.SetHeight( 60 );
if ( my_door.Open() )
if ( my_door.GetMaterial( ) == wood
)
// ERROR! You can't access
private members!
// ERROR! Argument types don't
match!
// ptr_to_door now points to the
"another_door" object
// another_door is now made of wood
// are we able to Close another_door?
You may ask "Why would anyone want to go to so much trouble to make attributes private?". That's another one of the benefits of C++. It's called "information hiding". It means that if I design a Door object and write the code for it, you don't have to know how I am storing things internally to be able to use this Door object. All I need to do is provide you with a header file that contains the "class" definition of the Door object and you will be able to pass parameters (arguments) to my methods (functions) without having to know how I store things inside the Door object. The C++ compiler will make absolutely sure that you are passing the correct types into these functions (like above, you can't set the door color to "stone"). This type checking is one of the most powerful features in C++. I mentioned that C++ is an object-oriented language. One of the advantages of objects is that you can have one object inherit properties from another object. The best way to determine if an object can inherit from another object is to check for the "is a" relationship. For example, if you had a Vehicle class, it might have color, weight, and number of wheels as attributes. You could create a Bicycle class that inherits from the Vehicle class since a Bicycle "is a" Vehicle. You could also have an Automobile class inherit from the Vehicle class since an Automobile "is a" Vehicle. You could not (should not) have an Automobile class inherit from a Bicycle class since an Automobile is NOT a Bicycle. Let's look at some examples of how to model these objects using C++. Here's the Vehicle class with attributes and methods: enum Color {red, green, blue, black, white, yellow, orange, purple}; class Vehicle
Color color;
public: virtual void SetColor( Color value
) { color = value; }
Here I've used a shorthand form of the Vehicle:: function definition. The following code inside the Vehicle class… virtual void SetColor( Color value ) { color = value; } …is equivalent to… virtual void Vehicle::SetColor( Color value )
…it's just a shorter way of writing the same thing. The "virtual" keyword before the function definition tells the C++ compiler that these functions will exist in this object and in any object that inherits from this object. The class that is being inherited from is called a "base class" (Vehicle in this case). The class that is inheriting from another class is called the "derived class". Now let's create a Bicycle class that inherits from the Vehicle class… class Bicycle : public Vehicle
int number_of_gears;
public: void SetNumberOfGears( int value
) { number_of_gears = value; };
Let's also create an Automobile class that inherits from the Vehicle class… class Automobile : public Vehicle
int number_of_cylinders;
public: void SetNumberOfCylinders( int value
) { number_of_cylinders = value; };
Now we can write the following C++ code to use the Vehicle, Bicycle and Automobile classes… void main(void)
v.SetColor( white );
// some kind of white vehicle
bike.SetColor( blue );
// the bicycle is blue
if (bike.GetMaxSpeed( ) > 30)
// get the maximum speed of this bicycle
car.SetNumberOfCylinders( 4 );
// this car has 4 cylinders
if (car.GetHorsePower( ) > 350)
// get the maximum horsepower of the car
Notice that we can use the functions of the base class in the derived classes without having to explicitly copy them. If we wanted to change the behavior of the functions (methods) in the derived class we can do that as well. Here is an example with the function in the derived class that is different from the function in the base class… class Bicycle : public Vehicle
int number_of_gears;
public: void SetNumberOfGears( int value
) { number_of_gears = value; };
void SetNumberOfTires( int value
) { printf("can't set number of tires!\n"); }
Notice that we have overridden the base class functions SetNumberOfTires and GetNumberOfTires for the Bicycle class. The Bicycle class prints out an error message when you call the SetNumberOfTires function and it will always return 2 as the number of tires when calling the GetNumberOfTires function. The SetNumberOfTires and GetNumberOfTires functions for the Automobile class still behave exactly the same as in the Vehicle base class. When looking though the Half-Life SDK, you will see many cases where classes will inherit from other classes and those classes, in turn, may have inherited from other classes. Refer to the Half-Life SDK page for more details on the C++ classes used by the Half-Life SDK
|