Al is a DDJ contributing editor. He can be contacted at firstname.lastname@example.org.
It's August in the mountains of central eastern Pennsylvania. We're here in the RV for Judy's annual family reunion, to be hosted this year at the farm where she grew up. The drought ended last week with some heavy rain, and everything looks green again, although the crops that my father-in-law planted this spring suffered the effects of too much heat and too little water. There's not much to pick.
The farm sits on the southern side of a small mountain range overlooking a wide, green valley. The tiny town of Brandonville nestles at the base of the valley. During the winter when the trees are bare, you can see a few rooftops down there. This time of year only a distant neighbor's farmhouse reminds you that there is anyone else in the world at all. If you are accustomed to the sounds of a city or live anywhere near an interstate highway you would be stunned by the silence here. My father-in-law is 80, has been a farmer all his life, and has owned and worked these 40 acres for the better part of 50 years. His comment when I marvel over the spectacular view is, "If it wouldn't be for those damn trees, maybe we could see some more of the town."
This trip brings to a conclusion a two-week visit to our house in Florida by our four grandchildren, ages five, seven, seven, and nine. They returned with us to rejoin their parents who look rested and content. You don't want to know how I look. I'll spare you the details of what it's like to keep four little people entertained, fed, clean, well-behaved, out of trouble, and from killing one another from morning to night when you are not used to doing it and they know it. I will say this much: If you want to know anything at all about the Cartoon Network, Power Rangers, or Pokémon, just ask me.
That hectic visit was not the only harried experience brought to a close this week. I just completed work on the sixth edition of a C++ tutorial book called Teach Yourself C++, published by MIS:Press, which is now owned by IDG Books, who publish all those For Dummies... books. (There is a C++ for Dummies, written by someone else, but I've never read it. I don't believe that dummies can do C++.) The first five editions of my book reflect the evolution of the C++ programming language as it has been implemented on PC platforms and as the ANSI/ISO standardization effort has proceeded. I didn't plan it that way. The language kept growing and changing, the compilers kept upgrading, and I kept revising the book. The sixth edition will be the first one to be published since the Standard was approved.
The sixth edition departs from the traditional book-with-code format that I used in the first five editions. Some publisher-type suits in positions of influence took some of the money they made by selling books to all those dummies, acquired MIS:Press, took a look at its inventory of titles, and decided that what had been a best-seller needed to be fixed and made more "visually appealing." Publishers, you see, know much better than authors and readers what constitutes a good programming book and what appeals to programmers. I don't know how they know that, but they do. Just ask one of them.
The new layout uses what they call a "spread" format. A spread comprises two facing pages with narrative text and snappy "visual elements" like hints, references, and notes on the left page and more visual stuff -- figures, screen shots, and so on -- on the right. Each such spread teaches what they call a "task" or "concept." They developed this format for books that teach things that have many visual elements, such as applications, HTML, and Visual Basic, and they think that it should work for advanced programming language books, too. Programming books for the MTV generation, the sound bite set, the People magazine crowd. Short sentences, lots of eye candy. Too many words and not enough pictures scare those dummy book buyers off. Before long, computer books will include a companion package of crayons instead of a CD-ROM.
Visual appeal, that's what sells. But with a generic C++ book, the only thing visual is source code and program output. Discreet lessons about C++ often involve more code than you can get on a page, or more text, or too little code to have its own page, or too little text, or some combination of all that. Rarely does a specific lesson involve exactly enough text and code to fit this new, visually appealing, Johnny Bravo, dumbed-down format. Try, for example, to fill two pages explaining and demonstrating what an int is and how to instantiate one. Try to explain and demonstrate "explicit specialization of a member of a class template partial specialization" in only one page of text and 30 lines of code. Try explaining to a development editor that there are no pretty CROSS REFERENCE visual elements with this concept because THERE IS NOTHING TO CROSS REFERENCE. Duh. Consequently, an author spends a great deal of time contriving content in some cases and sacrificing content in others to force the problem to fit the solution. Writing this book was not an easy experience. I'll take rowdy grandchildren every time.
Don't feel too sorry for me, though. I whined a lot throughout the project, and they gave me more latitude than I think they would have liked. Mine was the first programming book in the new format and we were learning about it together.
It was my hope that the sixth edition of Teach Yourself C++ would be the last one, particularly given the pain that writing it involved. The C++ Standard is approved and the language is well-defined and understood. However, the last several editions of the book included compilers on the companion diskette and, later, the companion CD-ROM, and I am not willing to sacrifice that feature. As we speak, I do not have a standard conforming C++ compiler and library that I can freely distribute. The fourth edition included the DOS DJGPP port of the GNU command-line compiler. The fifth edition included the Cygnus gnu-win32 port of the GNU C++ compiler along with a front-end Windows 95-hosted IDE named Quincy 97 that I developed for this purpose. The sixth edition will include an improved Quincy 99 with the mingw32 port of the Egcs 1.1.2 compiler, which is a closely conforming C++ compiler. Its library, however, is still the old one, so my book, which purports to be about Standard C++, is unable to demonstrate some nifty features of the Standard C++ Library, such as stringstreams, wide-character streams, and so on. This means that whenever they get all that stuff working, I'll be looking at doing a seventh edition. Oh, the pain.
Frameworks, Graphics, and C++
Although my new edition promises to be a hot seller (according to the suits), most of you will not need to read it. Most readers of this column already know C++. Many of you have told me that you learned C++ from earlier editions of the book. (You know, the ones in the old format that wiser heads assure me no one would ever buy.) But during its development, I learned some new and better ways to teach some difficult subjects. Difficult because arcane concepts need concrete examples.
One of the things that the mingw32 port of Egcs adds to the compiler is support for Windows applications development with the Win32 API. Ho hum. But wait. This feature opened a window of opportunity that I did not have with earlier editions -- the ability to demonstrate many of the features of C++ and object-oriented programming by using simple graphical applications.
In the old days, if you wanted to write about graphics on a PC platform, you had to spend some time talking about VGAs, XVGAs, and the like. Open any graphics programming book from that time and you'll find lots of details that you don't want to know about. The authors had no choice. If they were going to get their example programs running and displaying graphical images, they had to deal with the hardware. GUI platforms obviate all that low-level stuff by putting a device-independent layer between the programmer and the hardware.
A C++ tutorial book should teach C++, not some GUI API. But there is a compelling reason to use a GUI to teach C++. Nothing demonstrates the properties of object-oriented programming tools better than a simple graphical class library and a GUI simplifies the graphical parts. Every programmer who has ever written or used graphical rendering programs that draw shapes on the screen can immediately understand polymorphism when you explain it in terms of abstract and concrete shape classes. The abstract base shape class knows nothing about specific graphical shapes other than the properties that they all share -- position, rotation, and so on. Concrete shape classes derived from the abstract shape know how to draw, scale, transform, and rotate themselves. Early works on OOP missed the boat on this one by trying to use examples about furniture, insects, toasters, and such to explain class hierarchies. These are not things that you typically deal with. Graphical objects are, and they are visual things that are easily demonstrated with concrete examples. More "visually appealing," don't you know.
There is another reason to use a GUI to teach C++. You don't want to burden the student with details of the API, which is a course in itself, yet the example programs need the API to display the windows. To hide those details, you can provide a simple framework. Most C++ programmers use GUI frameworks such as MFC. By offering early exposure to a simple framework, you are preparing the student for the real world.
To teach all these things, I built a simple framework called TYFC, for "Teach Yourself Framework Classes." Catchy, huh? The version I discuss here is more advanced than the one in the book. I have experimented with TYFC to further examine its potential as a teaching aid, and this discussion reflects that research.
TYFC implements an abstract base class named TYFCApp, from which the application program derives a class. TYFCApp is small, consisting of one header file, tyfc.h (available electronically; see "Resource Center," page 5), which declares the TYFCApp class, and one source code file, tyfc.cpp (available electronically), which defines the member functions. You do not need to understand the implementation details of TYFCApp, which teaches the lesson that hiding details of implementation raises the programmer's level of abstraction.
You are allowed to peek, however. Another lesson to learn about C++ is that although the details are said to be hidden, they are actually mostly in view in the class declaration and completely in view in templates. You can hide nontemplate member function definitions, but I prefer that the source code be available, if only for documentation.
The application program derives a class from TYFCApp. The derived class represents the application, and its constructor specifies to the base class constructor the size of the application window and its caption. The derived class overrides the base class's pure virtual Initialize function. The program instantiates an external object of the derived class. As a result of that instantiation, TYFCApp creates the window and calls the derived class's Initialize function, which must put together something to display. textgl.cpp (available electronically) demonstrates the application program's use of the framework. Observe that the application has no main function. The framework provides it, in this case, a WinMain function, a detail that TYFC hides from you, another lesson to be learned. The WinMain function ensures that there is an instantiated derived TYFCApp object somewhere (its constructor records that fact, which is why the application object must be external), creates a window, and enters the usual message dispatching loop. The application program's Initialize function instantiates some graphical objects and calls addshape to add them to the display, in Figure 1.
TYFCApp, being a teaching vehicle, is only for static graphical displays, although it could evolve into a much larger framework. It knows about an abstract base class named Shape, and it maintains an std::list<> container of pointers to Shape objects, teaching the student that standard containers are easier to use than home-grown ones. TYFCApp also demonstrates polymorphism. Whenever the run-time system sends the WM_PAINT message to the application window, TYFCApp calls the draw function for each of the Shape objects pointed to by entries in the list container. The draw function in the Shape class is a pure virtual function, so the pointers have to be pointing at objects of classes derived from Shape, and those classes must have overriding versions of the draw function.
I used an std::list<> container for the Shape pointers, because a future version of the framework might need to know about and maintain the Z order of graphical objects. A list container is a good vehicle for reordering the objects it contains. Another lesson taught.
All TYFCApp knows about graphics is how to list Shape pointers and call their draw functions and how to draw a single point at an x/y coordinate on the screen. It adds shapes to its list when the derived class's Initialize function calls the addshape function. The application must use a graphical class library to exploit these characteristics. Win32 supports higher graphical abstraction, but TYFCApp's purpose is to teach at lower levels. All we want the graphical engine to do is open a window let us draw pixels.
graphics.h derives classes from Shape, and it has several lessons to teach. First is the example of concrete classes defining the polymorphic behavior of their common abstract base class, which is the original reason for these libraries. But other lessons fell out of the exercise.
The first such lesson is about a different kind of abstraction, the kind you implement with templates. Templates aren't just for containers, they are also good at expressing abstractions. In this case, the graphical library in graphics.h does not need to associate with the specific graphical engine that TYFCApp implements. That detail is provided as a parameterized type, which makes graphics.h and its concrete shape classes portable to other graphical engines. The engine and the library share only the knowledge of the abstract base Shape class (available electronically), which is independent of either of them. To port graphics.h to a different graphical engine, you could put a wrapper around the engine to contain and manage shape pointers, provide the addshape and drawpoint functions, call the application's Initialize function, and call the shape objects' draw functions.
The next lesson is about specialization. Given that some graphical engines support higher level drawing functions, you can specialize the draw member functions for instantiations with those engines. Graphics.h implements the Bresenham line-drawing algorithm and the usual circle-drawing algorithm that plots points around the circle by using radians, sines, and cosines. These algorithms are nice for teaching how graphical objects are drawn, but they are slow and usually unnecessary. You can specialize the draw member functions for the Line and Circle template classes when they are instantiated for graphical engines that draw these things for you.
The last lesson from graphics.h is about namespaces. Graphics.h defines a Line class, a Rectangle class, and a Circle class. These are nice, meaningful names -- the kind of names you like to give to things in a program. There is a catch, however. Somewhere in the mingw32-egcs 1.1.2 implementation of the Win32 API global namespace is something named Rectangle. Graphics.h puts its classes in a namespace to isolate its names from the global namespace and, consequently, demonstrates the utility of the C++ namespace feature.
The further I get into this specific teaching paradigm, the more I learn about how a simple graphics library can teach C++. Eventually the library will become too complex to serve that purpose, whereupon it might become a mechanism for teaching graphics programming in C++. And thus what started out to be a simple example of a complex subject surprises us when it demonstrates through its own growth how we learn things and how we ought to teach things. Sometimes you just can't see the town for the trees.
Copyright © 1999, Dr. Dobb's Journal