Letters to the editor may be sent via email to cujed@cmp.com, or via the postal service to Letters to the Editor, C/C++ Users Journal, 1601 W. 23rd St., Ste 200, Lawrence, KS 66046-2700.
Scott Meyers writes:
I just about popped my keycaps when I read Herb Sutters September column and Chuck Allisons editorial endorsement of its advice regarding virtual functions. Herb advocates the use of Template Method in preference to public virtual functions. Herb is entitled to advocate anything he likes, of course, but he also implies that this advice has become accepted wisdom in the C++ community. For example, he describes the code using Template Method as more modern and states that the foundation for his advice is that weve gained experience. Chuck backs up this claim, pointing out that the idea is not new and is found in the iostream library. What Chuck doesnt mention is that thats about the only place its found.
As an experiment, I took a look at two libraries that I think can reasonably be termed modern: Andrei Alexandrescus Loki (available at <www.awl.com/cseng/titles/0-201-70431-5/loki.zip>) and the sources at Boost (available at <www.boost.org/more/download.html>). Loki is heavily template-based, and there are very few virtuals, but all of the ones I saw were public. As for Boost, I counted 159 virtual functions in the various libraries, 149 of which were public.
I then decided to check some modern C++ books to see what they had to say. My first stop was Koenigs and Moos Accelerated C++. The book has little to say about virtuals, but all the virtual functions I saw were public. I then turned to the Special Edition of Stroustrups The C++ Programming Language. Almost all the virtuals I found were public, and I was especially interested to note the example in section 15.3.1 where a design feature Stroustrup points out that a public virtual calls a protected nonvirtual!
None of this is to say that Herbs advice is bad. Whether it is is immaterial. Rather, I think its important that CUJ carefully distinguish between what individuals believe and what the C++ community as a whole appears to endorse. (The latter is tricky, because, as Stroustrup has pointed out, nobody knows what most C++ programmers are doing.) Herb has influence and CUJ has influence, and when they claim that Template Method is preferred to public virtuals by good programmers writing modern C++, readers are likely to believe them. For Herb to advocate his personal belief and for Chuck to second him is entirely appropriate. However, to suggest that the debate is already over and Template Method came out on top, well, as I see it, thats just wrong.
Herb Sutter responds:
Thanks for the note. I wasnt trying to foist off this idiom onto an unsuspecting world by claiming that its universally accepted and theres no more room for discussion. But what I wrote is true: we as a community have learned the value of nonpublic virtuals in general, and, more recently, private virtuals in particular. Consider two data points:
- The C++ Standard library overwhelmingly makes its virtual functions nonpublic. To amplify what Chuck said about the standard library, I counted all of the nondestructor virtual functions in the entire C++ Standard library. There are 148, not counting duplicates in template specializations. Of the 148, 142 are nonpublic. There is only one virtual function that is public std::exception::what and its five overrides. (Yes, the nonpublic virtuals are protected, not private as I advocated. In many cases, they dont need to be protected and should be private, but after all I did say that as a community weve been learning.)
- The experts discussing this question advocate making virtual functions private by default. There have been recurring discussions among experts about this on the C++ newsgroups since about 1997 in particular. Note that this isnt just idle banter, but public discussion among experts that includes dispensing advice to nonexperts. Todays consensus among those participating in the discussions is that private virtual by default is a good idea. Notable standards committee members and authors who have written publicly in support for the idiom during 1999-2001 include Dave Abrahams, Francis Glassborow, Jim Hyslop, James Kanze, Dietmar Kuehl, Nathan Myers, and of course Chuck Allison and myself.
I know of only two experts who disagree(d) with the advice to make virtual functions private by default: for a time James Kanze switched to arguing for making virtual functions protected by default (still not public), but he has switched back to advocating that they be private by default. More recently, Kevlin Henney has argued against the private virtual advice on grounds that include that the idiom needs a better name than Template Method because its much more specific (true, I now call it the Non-Virtual Interface idiom, or NVI), that inheritance-based designs in general are overused and often there are better alternatives (I agree, and NVI is not intended to promote 1990s-style inheritance-heavy designs; but once you do decide to have a virtual function, NVI is presented as a better technique for implementing it), and that using NVI could lead to more-brittle base classes (debatable, and Im game to debate it). Kevlin and I plan to coauthor a Sutters Mill column on this topic soon to summarize our analysis of this idiom.
Of course, there are special cases where virtual functions have to be public, such as in the case of a destructor (as I pointed out in my article) or when you need to take advantage of covariant return types, which would be prevented by a nonvirtual wrapper. But I believe that what I said continues to be true: virtuals should be private by default. The standard library itself, from early-1990s vintage drafts to the present official standard, already implements virtuals should be nonpublic by default. Since then the majority of experts who are discussing this topic have further refined this to virtuals should be private by default. My article was intended to document what we as a community have come to understand, based on the current thinking of the experts who are actively discussing it.
Chuck Allison adds:
It seemed as good a time as any to take the lid off a technique that pervades the Standard C++ library. Its use may indeed not be as common as Herb made it appear, but whether it is or not, its certainly worth considering.
Dear CUJ,
I enjoyed Bob Lorenzens article about image warping including the section about the Bresenham algorithm (September 2001).
I implemented the algorithm many years ago in Z-80 machine code to draw (really crude, but extremely fast) graphics on an 80x25 text terminal.
I was impressed by its simplicity, but, as I recall, and as Bobs description suggests, the algorithm never draws multiple pixels per iteration along the long dimension of the line. The implementation producing the example is therefore flawed as it has generated extra pixels. Or maybe the example was created manually in a graphics application?
Details, details...
Regards,
Niels Jakob Darger
Dear Niels:
Thanks for taking the time to respond to my article.
Rest assured that the examples were indeed my kittens processed with the sample app that was posted on the CUJ website. I will be more than happy to send you the Windows 9X/NT/2K/ME sample app via email (320K zipped) if you send me an email directly and request it.
What I failed to explain clearly was that this is a brute force technique. Rather than compute what the optimal destination is, I simply write out pixels so the last one written wins.
Take a simple example. Given a 10x10 pixel source, if we go to create a 5x5 pixel destination, my algorithm will write each of the destination pixels four times. The theorists would want me to arrange to throw out the 75 pixels instead of writing them. I maintain that the output inefficiency is far more efficient than computations required to skip the input pixels.
Regards,
Bob
Dear CUJ,
Ive just read with interest the article A C++ Debug Stream for Win32 by Mark Nelson (September 2001) and would like to describe the method that I use.
The C/C++ code-base that I work on is ported between several versions of Unix and Windows NT/2000 and, having been worked on for several years, contains debug output written with C printf and C++ iostreams. Rather than re-write this legacy code to use a new class (as in the above article), you can in fact re-open the standard streams to the console. The type of code that Ive used to do this is shown below:
// Allocate a console window for this // process AllocConsole(); // Create a new (bigger) screen buffer // for it HANDLE hCon = CreateConsoleScreenBuffer (GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CONSOLE_TEXTMODE_BUFFER, NULL); if (hCon != INVALID_HANDLE_VALUE) { COORD size; size.X = 80; // Make the buffer 1000 lines... size.Y = 1000; // ... and make console use it // (it will setup a scroll-bar) if (SetConsoleScreenBufferSize(hCon, size)) { SetConsoleActiveScreenBuffer(hCon); } } // Set the title of the debug window SetConsoleTitle(Debug Output); // Reopen C output streams to the // console, then re-sync IOS (void) freopen(CONOUT$, w, stderr); (void) freopen(CONOUT$, w, stdout); ios::sync_with_stdio();Using this allows code written with the printf family or iostreams to write into the debug window without any further changes. For systems with large amounts of legacy code ported from console-based systems, it saves significant rework.
Gavin Ridgway
Hi Gavin,
Yes, this is a great piece of code to use, particularly when faced with legacy or multi-platform software. Thanks for the feedback!
Mark Nelson