Part 3: C++ - A Language of Liberation

By STEVE GOSCHNICK

 

I have been a "frustrated programmer" for 13 years. No, I don't mean that I have been in the wrong job. Rather, the programming languages and tools I have used over that period, never allowed me to program anywhere near the rate I wanted to. Very much like a jogger not being able to get to a speed or maintain a rhythm, that will allow him to cover a great distance.

Many great feats of programming have been done by people when they were young and single (eg. PC software pioneers, Bill Gates with his 4K BASIC interpreter, or Dan Bricklan with VISICALC). In fact, programming is viewed by many IT managers as a young persons occupation. I was jolted from such a perception when as a Manager, I was involved in hiring a Consultant to do some C programming in WINDOWS, when Version 1 was the current version. The only person who was qualified and up to scratch in Windows, was a seventy year old C wizard, who turned out to be just what we needed and did an outstanding job. (Returning to the PC software pioneers. C. Wayne Ratliff, author of DBASE II, had a prior career in computing 1969-82 working for such people as NASA, before his commercially successful PC product. While this doesn't make him pensioner material, he was no boy genius either.)

The reason why young programmers can be more productive code-cutters, is more due to their position in the Life Cycle than their age. Big programming projects in 3GL's or less, are long draw-out affairs, where your concentration must be maintained for several months or even years on end. Having ankle-biters, commitments and an associated constant stream of bills to pay, is clearly distracting to prolonged software development. I can personally vouch for that.

Most senior programmers tend to solve this problem by either remaining childless, or going into management, or a consultant advisory role, or package evaluation, or training co-ordinator or else some glorified clerical position. I tried a management position that was a combination of most of the above, but it didn't like me and I wasn't ready to hang up my programming boots. So I went back to what I had enjoyed best. But I went in search of a less demanding yet more capable language. One where I could pick up the pieces of code any old time and make progress without too many steps backward. A language in which one programmer could feasibly tackle the increasing complexities of modern packages, such as slick user interfaces. This demanding wish list for a language was shaping up to be a search of Holy Grail proportions. Could such a mythical language really exist?

The search was worthwhile for it led me to Object Oriented Programming (OOP) in general and C++ in particular. It does indeed enable you to come back to the code any old time, and get on with the job where you left off, which may have been weeks or even months ago. With C++ you can maintain a steady speed of progress. Your stage in the Life Cycle is no longer of primary importance. C++ can be a programmer’s language of liberation then. Learning it is worth the effort, I can assure you. But be careful though, it can bring on a mid-career change in direction.

 

The Second Example.

 

Inheritance:

This month we do our second example of developing and using classes of objects in C++. The code here not only follows on from that in my last C++ article, but it is built upon it. Our new Class is called the Button Class, as in a graphically presented push-button on the screen (see the buttons in Fig. 1 - a calculator interface screen, which is this months example application program, CALCFACE.CPP.)

The Button Class is literally derived from our first Class Bevelled_box, and as such it INHERITS all of the features (internal data plus Methods) of Bevelled_box. We add the appropriate new features to such a child Class, on top of those it inherits from its parent, to achieve our particular purpose at hand.

The particular purpose we have for Button Class, is to display a bevelled box on the screen, but with an additional inscription on the top face. This makes it clearly look like a real world button, like that on everyday objects such as a keyboard, a video player or in our case a calculator.

The only enhancement visually to the parent Class then, consists of this screen-text on top. But we also wish to store the inscription text internally in the object, and we want to be able to query a button object for its current position. eg. Is it currently pressed or not pressed? We also want some smarts built into the object so that it automatically scales the text to be a user defined proportion of the height of the button. eg. 0.5 for half of the top face.

Again, as with Bevelled_box, we declare the Classes particulars in a Header file, and define the Class in an implementation file.

 

LISTING 1 - the Button Header File.

  1. // Listing 1.
  2. //--------------------------------------------------------------------
  3. // DOS FILE: BEV_BOX.HPP
  4. // CLASS of Bevelled Boxes. Header File.
  5. //
  6. // A boxes height and width may be defined (in pixels) when
  7. // an OBJECT of type Bevelled_box is defined. The starting
  8. // x and y coords are also set then. As is an aspect ratio
  9. // for the particular graphics card being used, iff you want
  10. // the METHOD's to allow for non-square screen pixels. Else pass 1.0.
  11. //
  12. // Language: C++, Turbo C++ V1 Date: Jan'91.
  13. // Author: Steve Goschnick.
  14. // Copyright: SOLID SOFTWARE.P.O.Box 218,Belgrave,VIC,3160.
  15. //--------------------------------------------------------------------
  16. #include <stdio.h>
  17. #include <alloc.h>
  18. #include <dos.h>
  19. //--------------------------------------------------------------------
  20. class Bevelled_box {
  21. protected:
  22. int box_startx;
  23. int box_starty;
  24. int box_width;
  25. int box_height;
  26. int bevel_width;
  27. float aspect_ratio; //Pixel aspect ratio.
  28. char top_colour;
  29. int box_fill;
  30. char north_colour,east_colour,south_colour,west_colour;
  31. void Draw_one_bevel(int *, int fill_colour, int fill_pattern);
  32. public:
  33. Bevelled_box (int startx, int starty, int width, int height,
  34. int bev_width, float aspect);
  35. ~Bevelled_box (){}
  36. void Set_colours(char top, char north, char west,
  37. char south, char east);
  38. void Display();
  39. void Set_fill(int fill);
  40. };
  41. // End of Listing 1.

 

Look now at the file BUTTON.HPP (See Listing 1.) We first reference the parents include file "BEV_BOX.HPP". Then in the opening Class statement:

class Button : public Bevelled_box{...

a parent called Bevelled_box is identified and preceded by the optional word public. This public adjective, means that objects of this derived Class will be able to call (message) Methods defined in the parent Class. If this public is absent, then only the Methods of the derived class can call the Methods of the parent.

Every object of a derived class contains its own copy of the private data of its parent class (unless the variable is declared static) as well as its own private data. So the variables declared after the protected clause, are additional data items to those it inherits from the parent Bevelled_box. ie. In addition to having the items box_startx, box_starty, box_width etc., it has text_font, text_size, text_prop, text_display, text_colour and pressed.

Text_prop is a measure of the height of the text on top of the button, represented as a decimal fraction of the height of the button top. Ie. 0.75 means the text height would be three-quarter as high as the top face. The object auto-scales the text by itself, which is a must in these days of multiple video cards and multiple screen fonts.

Text_display is a pointer to a character string, which actually contains the text to be displayed on the button top. eg. "Enter" if it was to display an ENTER button on the screen.

Pressed can take on a value of zero or one. It is used to simulate a push-button such as those on a video player. Zero is UP, one is PRESSED.

The other new object variables, shouldn't need explanation given their names. Although text_size is not what it sounds like. It actually takes on a value of either zero or one, which then affects the various Turbo C++ graphics functions that put fonts to the screen. Turbo has two types of fonts, one bit-mapped screen font, and four vectorised (mathematically defined) screen fonts. The other graphics functions treat these two types of fonts differently when it comes to scaling. But I am not going to go into the specifics any further. It's all in the Turbo C++ reference manual.

After the public clause, the Constructor, Destructor and the Methods Set_text_colour, Display_text, Push_button and Button_state are declared.

 

LISTING 2 - the Button Implementation File.

  1. // Listing 2.
  2. //--------------------------------------------------------------------
  3. // DOS FILE: BUTTON.CPP
  4. // CLASS of graphic Buttons. Implementation File.
  5. // This CLASS is derived from CLASS Bevelled_box.
  6. //
  7. // This file contains definitions of the Button Constructor,
  8. // as well as the following Button METHODS:
  9. // Set_text_colour(char txt_colour);
  10. // Display();
  11. // Push_button();
  12. // Button_state();
  13. // Language: C++, Turbo C++ V1 Date: Jan'91.
  14. // Author: Steve Goschnick.
  15. // Copyright: SOLID SOFTWARE,P.O.Box 218,Belgrave,VIC,3160.
  16. //--------------------------------------------------------------------
  17. #include "BUTTON.HPP"
  18. #include <graphics.h>
  19. //--------------------------------------------------------------------
  20. // The Constructor, which in-turn initialises "parent" constructor...
  21. Button::Button(int start_x, int start_y, int width, int height,
  22. int bev_width, float aspect,
  23. int t_font, float t_prop, char * button_text)
  24. : Bevelled_box (start_x, start_y, width, height,
  25. bev_width, aspect )
  26. {
  27. text_font = t_font;
  28. text_prop = t_prop;
  29. if (text_font == DEFAULT_FONT)
  30. text_size = 1;
  31. else
  32. text_size = 0;
  33. text_display = button_text;
  34. //Now set a default colour for the text...
  35. text_colour = EGA_WHITE;
  36. pressed = 0;
  37. }
  38. //--------------------------------------------------------------------
  39. // METHOD used to set/reset the buttons text colour...
  40. void Button::Set_text_colour(char txt_colour)
  41. {
  42. text_colour = txt_colour;
  43. }
  44. //--------------------------------------------------------------------
  45. // METHOD used to centre, auto-scale and display button text...
  46. // Calls these standard Turbo C++ functions: setcolor,settextstyle,
  47. // setusercharsize,settextjustify,moveto,textheight,outtext.
  48. void Button::Display()
  49. {
  50. Bevelled_box::Display();
  51. // Find the (x,y) coordinate of the centre of the
  52. // top of the botton...
  53. int mid_x = box_startx + box_width/2;
  54. int mid_y = box_starty + box_height/2;
  55. // Set text font, and auto-scale text height to the desired
  56. // proportion of the box height.
  57. // Then print the text to screen, centred in the top of
  58. // the button...
  59. if (text_prop <= 0.0) text_prop = 0.25;
  60. settextstyle(text_font,HORIZ_DIR,4);
  61. // Height calculations are in pixels...
  62. int height_desired = (int)(text_prop*(box_height - 2*bevel_width));
  63. int current_height = textheight(text_display);
  64. settextstyle(text_font,HORIZ_DIR,0);
  65. setusercharsize(height_desired,current_height,
  66. height_desired,current_height);
  67. setcolor(text_colour);
  68. settextjustify(CENTER_TEXT,CENTER_TEXT);
  69. moveto(mid_x,mid_y);
  70. outtext(text_display);
  71. }
  72. //--------------------------------------------------------------------
  73. // METHOD used to toggle the button.
  74. void Button::Push_button()
  75. {
  76. if (pressed) pressed = 0;
  77. else pressed = 1;
  78. }
  79. //--------------------------------------------------------------------
  80. // METHOD used to determine if the button is ON or OFF.
  81. int Button::Button_state()
  82. {
  83. return pressed;
  84. }
  85. // End of Listing 2.

 

The actual definitions of the Methods declared in BUTTON.HPP live in file BUTTON.CPP. All are prefixed with Button:: to qualify them.

The Constructor Button::Button is first, looking a bit more complex than the Constructor for its parent Bevelled_box, yes? This is because it must also fire-up its parents Constructor when a Button object is declared. Hence parameters start_x, start_y, width, and height, must be defined with a Button object, and they are passed on to the parent object. Apart from this dramatic opening statement, the rest of the Constructor is just initialisation of variables. (DEFAULT_FONT is a standard Borland bit-mapped font.)

The Set_text_colour Method is the second easiest type of Method there is - a one liner.

The Display Method not only writes the text to screen, but before that it auto-scales the text according to the programmer supplied ratio text_prop. All the functions referenced in here are standard Borland C++ graphics functions.

An interesting thing about the Display Method, is that it overrides the Display Method it inherits from parent Bevelled_box because we have given them the same name. In fact it also makes a call itself to this parent Method, by prefixing the call with the parent name ie.

Bevelled_box::Display();

In C++, Methods can be overloaded. This means that there can be several different definitions of a Method with the same name. If each such Method has a different type or number of parameters, we don't have to worry about qualifying them when we call one. The compiler will work out itself which version we want, by the parameters we pass in our Message to the Object.

In C++ we can also define the operators for Objects. eg. We can write a function which processes the plus sign (+) and the objects either side of it, when we put a plus sign between two such object in an expression! This is termed Operator Overloading. ie. giving an operator several meanings.

The Push_button Method, simulates a toggle for a push-down, pop-up button. And Button_state returns the value of pressed so that you know whether, the button object is currently up or down. ie. You just ask the button in question using this Method.

We now compile this file (using the keys ALT+F9 in the Turbo C++ Integrated environment,) to BUTTON.OBJ. To create objects of the Button CLASS in our application programs, we simple list within our source code, the header file BUTTON.HPP as an include file, like so:

#include "BUTTON.HPP"

and then when we compile to a .EXE (using the keys CTRL+F9 in the Turbo C++ Integrated environment,) we link in the pre-compiled BUTTON.OBJ file via the PROJECT file. The PROJECT file simply lists all files that play a part in the making of the .EXE.

 

LISTING 3 - the CALCFACE Application Program.

  1. // Listing 3.
  2. //--------------------------------------------------------------------
  3. // DOS FILE: CALCFACE.CPP
  4. // An example application that uses the "Button" CLASS,
  5. // to create an image of a Calculator on screen.
  6. // It will run on all graphics cards (ie. it auto-scales),
  7. // but is really designed for VGA or EGA colour.
  8. // Language: C++, Turbo C++ V1 Date: May'91.
  9. // Author: Steve Goschnick.
  10. // Copyright: SOLID SOFTWARE.P.O.Box 218,Belgrave,VIC,3160.
  11. //--------------------------------------------------------------------
  12. #include "BUTTON.HPP"
  13. #include <graphics.h>
  14. #include <conio.h>
  15. #include <stdlib.h>
  16. #define ORIGIN_X0 0
  17. #define ORIGIN_Y0 0
  18. // Globals...
  19. float aspect_r;
  20. int screen_width, screen_height;
  21. // Function Prototypes...
  22. void open_graphics();
  23. //--------------------------------------------------------------------
  24. // MAINLINE.
  25. main()
  26. {
  27. int hi,wid,twinwid,gap=2,bev1=10,bev2=3,margin=10,centre;
  28. int x0,y0;
  29. char *name = "YOUR CALCULATOR";
  30. open_graphics();
  31. // Create calculator case with "Bevelled_box"...
  32. hi = screen_height;
  33. wid = int (hi / 1.60);
  34. centre = screen_width / 2;
  35. x0 = centre - wid*aspect_r/2; y0 = ORIGIN_Y0;
  36. Bevelled_box casement(x0,y0,wid,hi,bev1,aspect_r);
  37. casement.Set_colours(BROWN,LIGHTGRAY,LIGHTCYAN,DARKGRAY,LIGHTCYAN);
  38. casement.Display();
  39. // Create a black calculator display screen...
  40. x0 = x0 + (bev1 + margin + gap)*aspect_r;
  41. y0 = y0 + bev1 + margin + gap;
  42. wid = wid - 2*(bev1+margin+gap);
  43. hi = screen_height/10;
  44. Bevelled_box calc_display(x0,y0,wid,hi,bev2,aspect_r);
  45. calc_display.Set_colours(BLACK,DARKGRAY,LIGHTCYAN,LIGHTGRAY,LIGHTCYAN);
  46. calc_display.Display();
  47. // Give it a Brand name...
  48. y0 = y0 + hi + margin;
  49. wid = wid/2; hi = hi/2;
  50. Button brand(x0,y0,wid,hi,bev2,aspect_r,SMALL_FONT,0.5,name);
  51. brand.Set_colours(WHITE,LIGHTGRAY,LIGHTCYAN,DARKGRAY,LIGHTCYAN);
  52. brand.Set_text_colour(BLACK);
  53. brand.Display();
  54. // Now do all the calculator buttons...
  55. hi = wid = (int(screen_height/1.60)-2*bev1-2*margin-3*gap)/4;
  56. twinwid = 2*wid + gap;
  57. y0 = screen_height - bev1 - margin - wid;
  58. Button zero(x0,y0,twinwid,hi,bev2,aspect_r,SMALL_FONT,0.5,"0");
  59. zero.Set_colours(LIGHTBLUE,LIGHTGRAY,LIGHTCYAN,DARKGRAY,LIGHTCYAN);
  60. zero.Display();
  61. y0 = y0 - (hi + gap);
  62. Button one(x0,y0,wid,hi,bev2,aspect_r,SMALL_FONT,0.5,"1");
  63. one.Set_colours(LIGHTBLUE,LIGHTGRAY,LIGHTCYAN,DARKGRAY,LIGHTCYAN);
  64. one.Display();
  65. y0 = y0 - (hi + gap);
  66. Button four(x0,y0,wid,hi,bev2,aspect_r,SMALL_FONT,0.5,"4");
  67. four.Set_colours(LIGHTBLUE,LIGHTGRAY,LIGHTCYAN,DARKGRAY,LIGHTCYAN);
  68. four.Display();
  69. y0 = y0 - (hi + gap);
  70. Button seven(x0,y0,wid,hi,bev2,aspect_r,SMALL_FONT,0.5,"7");
  71. seven.Set_colours(LIGHTBLUE,LIGHTGRAY,LIGHTCYAN,DARKGRAY,LIGHTCYAN);
  72. seven.Display();
  73. y0 = y0 - (hi + gap);
  74. Button clear(x0,y0,wid,hi,bev2,aspect_r,SMALL_FONT,0.20,"CLEAR");
  75. clear.Set_colours(RED,LIGHTGRAY,LIGHTCYAN,DARKGRAY,LIGHTCYAN);
  76. clear.Display();
  77. x0 = x0 + (wid + gap)*aspect_r;
  78. Button divide(x0,y0,wid,hi,bev2,aspect_r,SANS_SERIF_FONT,0.4,"/");
  79. divide.Set_colours(YELLOW,LIGHTGRAY,LIGHTCYAN,DARKGRAY,LIGHTCYAN);
  80. divide.Set_text_colour(BLACK);
  81. divide.Display();
  82. y0 = y0 + (hi + gap);
  83. Button eight(x0,y0,wid,hi,bev2,aspect_r,SMALL_FONT,0.5,"8");
  84. eight.Set_colours(LIGHTBLUE,LIGHTGRAY,LIGHTCYAN,DARKGRAY,LIGHTCYAN);
  85. eight.Display();
  86. y0 = y0 + (hi + gap);
  87. Button five(x0,y0,wid,hi,bev2,aspect_r,SMALL_FONT,0.5,"5");
  88. five.Set_colours(LIGHTBLUE,LIGHTGRAY,LIGHTCYAN,DARKGRAY,LIGHTCYAN);
  89. five.Display();
  90. y0 = y0 + (hi + gap);
  91. Button two(x0,y0,wid,hi,bev2,aspect_r,SMALL_FONT,0.5,"2");
  92. two.Set_colours(LIGHTBLUE,LIGHTGRAY,LIGHTCYAN,DARKGRAY,LIGHTCYAN);
  93. two.Display();
  94. y0 = y0 + (hi + gap);
  95. x0 = x0 + (wid + gap)*aspect_r;
  96. Button dot(x0,y0,wid,hi,bev2,aspect_r,SMALL_FONT,0.5,".");
  97. dot.Set_colours(LIGHTBLUE,LIGHTGRAY,LIGHTCYAN,DARKGRAY,LIGHTCYAN);
  98. dot.Display();
  99. y0 = y0 - (hi + gap);
  100. Button three(x0,y0,wid,hi,bev2,aspect_r,SMALL_FONT,0.5,"3");
  101. three.Set_colours(LIGHTBLUE,LIGHTGRAY,LIGHTCYAN,DARKGRAY,LIGHTCYAN);
  102. three.Display();
  103. y0 = y0 - (hi + gap);
  104. Button six(x0,y0,wid,hi,bev2,aspect_r,SMALL_FONT,0.5,"6");
  105. six.Set_colours(LIGHTBLUE,LIGHTGRAY,LIGHTCYAN,DARKGRAY,LIGHTCYAN);
  106. six.Display();
  107. y0 = y0 - (hi + gap);
  108. Button nine(x0,y0,wid,hi,bev2,aspect_r,SMALL_FONT,0.5,"9");
  109. nine.Set_colours(LIGHTBLUE,LIGHTGRAY,LIGHTCYAN,DARKGRAY,LIGHTCYAN);
  110. nine.Display();
  111. y0 = y0 - (hi + gap);
  112. Button multiply(x0,y0,wid,hi,bev2,aspect_r,SANS_SERIF_FONT,0.6,"*");
  113. multiply.Set_colours(YELLOW,LIGHTGRAY,LIGHTCYAN,DARKGRAY,LIGHTCYAN);
  114. multiply.Set_text_colour(BLACK);
  115. multiply.Display();
  116. x0 = x0 + (wid + gap)*aspect_r;
  117. Button minus(x0,y0,wid,hi,bev2,aspect_r,SANS_SERIF_FONT,0.4,"-");
  118. minus.Set_colours(YELLOW,LIGHTGRAY,LIGHTCYAN,DARKGRAY,LIGHTCYAN);
  119. minus.Set_text_colour(BLACK);
  120. minus.Display();
  121. y0 = y0 + (hi + gap);
  122. Button plus(x0,y0,wid,twinwid,bev2,aspect_r,SANS_SERIF_FONT,0.2,"+");
  123. plus.Set_colours(YELLOW,LIGHTGRAY,LIGHTCYAN,DARKGRAY,LIGHTCYAN);
  124. plus.Set_text_colour(BLACK);
  125. plus.Display();
  126. y0 = y0 + 2*(hi + gap);
  127. Button enter(x0,y0,wid,twinwid,bev2,aspect_r,
  128. SANS_SERIF_FONT,0.10,"ENTER");
  129. enter.Set_colours(GREEN,LIGHTGRAY,LIGHTCYAN,DARKGRAY,LIGHTCYAN);
  130. enter.Set_text_colour(WHITE);
  131. enter.Display();
  132. char ch = getch(); // Wait for user to strike keyboard.
  133. closegraph();
  134. } // END OF MAINLINE.

 

With the simple enhancements to Bevelled_box represented in Button, we very quickly got a new Class of useful, highly reusable objects. The sample application program called CALCFACE.CPP (see Listing 3,) uses both the Button Class and its parent the Bevelled_box class. CALCFACE is simply a screen rendition of a calculator keypad and display panel (see Fig.1). It doesn't have the functionality of a calculator yet. But that would simply require capturing appropriate keyboard characters (or the mouse button pressed and the current cursor position), putting the numbers through one of four simple equations (ie. result=A+B,A-B,A*B,or A/B), and outputting the results to the calculator display! That is a good exercise for you.

Note the use of colour to enhance the interface, by differentiating the various groups of keys in blue, yellow, red and green. In particular the use of red and green according to our cultural associations with those colours. (The program is basically set up for an EGA 640x350x16 colour or VGA 640x480x16 colour, but it will still work on a CGA colour or a monochrome graphic video card. However you will have to change the colour settings passed to the objects, for the other cards).

In the METAGON game interface (see Fig. 2, this is a forthcoming game, I have written which uses Bevelled_box and the Button Class) I actually change the colour of the buttons in the top-right of the screen (using Bevelled_box's Method, Set_colours), during the programs execution, from red to green, or from green to red, to clearly and naturally let the 2 players know, who's turn it is, and which buttons they may choose from. Whether one of the players is the computer or both are humans, doesn't affect the program interface. While this colour business, has everything to do with interface design and cognitive human factors, and little to do with OOP specifically, note how easily Methods can support the design process.

 

Observations:

I won't take you through the code in CALCFACE.CPP, as it consists of little more than a series of Messages to Objects. First creating them and then telling them to display themselves at the appropriate locations on the screen. This repetitive nature of the code in CALCFACE.CPP brings to mind a few questions and highlights several things about application programs that use Classes of existing Objects:

- We may have been better off with an array of objects to represent the calculator buttons (at least the numeric buttons). C++ allows arrays of objects but it requires more thought about your Constructor/s. Just as we overloaded the Method Display in Button Class, we can have overloaded Constructors too. ie. We define several of them. An example of arrays of Objects will have to wait until another article, Jake willing.

- The whole of CALCFACE.CPP took me about 2 hours to develop, and as I mentioned in the first article, I am not a fast coder. The process mainly involved copying chunks of code and editing them (This was greatly enhanced by the programmers editor I used, called ED - which allows you to retain several copies of blocks of code in memory at the one time.) It may have struck you just how easily a higher-level graphic oriented editor could have churned out something like this code. In the near future we are going to see many graphic/icon based editors and higher level languages, that do indeed churn out sausage-like code. This will make OOP programming easier still further. And you can be near certain that the better ones will pre-compile to C++ for the execution speed that can be attained via it. And they will use existing libraries of Classes probably developed and compiled in C++, so that it is likely an investment now in C++ will keep paying down the ages.

 

Extensibility.

Our example this time covered Inheritance, enough to see the use of it and the benefits thereby attained. Yet there is an aspect of C++ Inheritance I haven't mentioned so far. You can develop your own offspring Class, even if you don't have the source code to the parent! This means for example, that if we only had the BUTTON.OBJ file together with the header file BUTTON.HPP, and we wanted to define a new child Class ourselves, we can still do it.

Let us say we where going to develop a computer version of the SCRABBLE board game. The Class SCRABBLE_TILE, is to look very much like the Button Class we developed here, but as well as having a letter of the alphabet, centred on the tile, we need a number in bottom-right corner of the tile face, to represent the tiles score.

No problem. We simple declare a new Class in a header file which inherits the features of Button, with a new Method that simply displays this score at the appropriate tile corner. We then define a .CPP file with just a Constructor, which apart from setting the score, also passes parameters down to the parent Button object, just as the Constructor of Button, passes parameters down to Bevelled_box. The only other Method to define here, is one to display the score. In other words, we can modify the features of .OBJ code for which we don't even have the source code. Not only can we add new Methods, we can overload (and therefore modify) existing ones.

As you can imagine this feature is very attractive to both software tool developers and the tool users. Developers are often reluctant to part with their source code for several good reasons. While most people think its just because they don't wish to sell off their trade secrets, a major consideration is also the support of the product. If you have the source code and you make some modification to it which introduces a bug, how can or why should the developer possibly help you? The converse argument from the software tool users point of view is: "How can you expects us to adopt your tools, when we don't have the source code, and so cannot modify their workings if our requirements vary slightly?"

The extensible nature of C++ .OBJ code, is an excellent compromise from both the tool developers point of view and that of the tool users.

 

Conclusions.

In these last two articles which carry examples, we have covered a good proportion of the prominent features of C++ and hence OOP. They have been: Data Hiding; Encapsulation; Constructors/ Destructors; Inheritance; and the Overloading of Methods, which is a part of what is termed Polymorphism. We haven't yet covered: Operator Overloading (mentioned, but no example); or Virtual Functions. This last feature being the main vehicle for Polymorphism.

Yet already, I hope the power of C++ is becoming apparent to you. As you can see, the work is in the developing of Classes for that is where the algorithms are stored. Using existing Classes is not difficult at all.

The two related classes we developed here, represent just two generations on a Class hierarchy tree. And are therefore fairly simple. But they are effective, as I am already using them to advantage in commercial programs. An extensive Class library might (I say might not typically, as there are not many C++ Class Libraries commercially available just yet), consist of scores of classes spread over a hierarchy tree covering 7 or 8 generations.

As an example, one Class library that did become available recently, is the "WIN++ Library" from Braise Computing Inc. in the US. Its purpose is primarily for Windows V3 program development, from within Borland C++ (the later, more expensive edition of Turbo C++). It has 99 Classes spread over 8 generations (See Fig. 3). A number of these classes duplicate what comes with Turbo C++ and Borland C++ (eg. the BCList family of classes contains child classes that implement the usual Linked-lists, Stacks and Queues - which you will also find in most text books on C++), but the Windows Control Classes family there-in, are much rarer tools, for they encapsulate the entire Windows V3 interface, in just 39 of those 99 Classes. However, Blaise are not likely to be the only game in Windowville for long, Borland themselves have recently stated that Object Windows, a Borland Class library for Windows development bundled with their Turbo PASCAL for Windows compiler, will also be available for their C++. This may have happened by the time you read this.

As you might imagine after our play here with Bevelled_boxes and Buttons, C++ and graphic interface environments like Windows V3, are the stuff that great technological marriages are made of. It is as if Windows has been sitting there on the shelf for 5 years, just waiting for OOP to come along and deliver it to the programming masses. If you have held back from programming Windows in C, you can probably easily save 6 to 12 months work, by doing it now in C++ using a Windows V3 interface Class library. As I said in my first C++ article, you would have spent your time most wisely during the lead-time for these Windows Class libraries to come to market, limbering up on the specifics of C++. As you no longer have to wait for the Windows Class libraries, the advice on the C++ direction, is now even more valid.

The above is not an endorsement of WIN++ in particular, just the approach, as I have not yet used or even cited the actual product. Don't necessarily be impressed with a large Class library. A library that consists of hundreds of poorly coded classes, is not worth more than one that implements a handful of classes very well. Nevertheless, Blaise Computing Inc. have built a good reputation in C and PASCAL tools, before their venture into C++ and Windows. That the classes in WIN++ hang together in a well defined hierarchy, is also an indicator of a well designed Class library.

Of course programming incorporating the Windows interface, is still far from the minds of may serious and recreational programmers. And you are more likely to be interested in programming in a very specific applications area, than in some general horizontal market. But the fact of the matter is, that there are very few commercial C++ Class libraries on the market at all just now. That is a part of the attractiveness of C++. It is not unlike the market potential of MS/DOS itself back in 1981. There was so much left to be done! The 3rd party Class library market is virgin territory. There will be structural engineering class libraries for structural engineers; robot control class libraries for manufacturing; accounting class libraries for accountants and small businesses; cartoon animation class libraries for cartoonists; etc, etc. So if you are in a niche field, with specific technical or empirical knowledge, why wait for the class library in your field of human endeavour to become available? Why don't you do yourself and your country a favour and encapsulate that knowledge in a resellable Class library of your very own!

 

Fig. 1 - The output from program CALCFACE.CPP, which uses the Button class.

Fig. 2 - A beta version of the upcoming computer rendition of the strategy board game METAGON, from Solid Software. Both the Bevelled_box and Button classes, were used to develop it.

Fig. 3 - The Class Hierarchy Chart for the WIN++ Class Library.

 

This article is Copyright: Steve Goschnick, 1991.