Path: senator-bedfellow.mit.edu!bloom-beacon.mit.edu!news.kei.com!nntp.coast.net!howland.reston.ans.net!usc!news.cerf.net!nic.cerf.net!mpcline From: mpcline@nic.cerf.net (Marshall Cline) Newsgroups: comp.lang.c++ Subject: C++ FAQ: posting #1/4 [IGNORE EARLIER POSTING!] Followup-To: comp.lang.c++ Date: 26 Apr 1996 21:21:59 GMT Organization: Paradigm Shift, Inc (technology consulting) Lines: 1205 Sender: cline@parashift.com Distribution: world Expires: +1 month Message-ID: <4lrepn$33c@news.cerf.net> Reply-To: cline@parashift.com (Marshall Cline) NNTP-Posting-Host: nic.cerf.net Summary: Please read this before posting to comp.lang.c++ Archive-name: C++-faq/part1_4 [PLEASE NOTE: PLEASE IGNORE THE EARLIER POSTING OF THE FAQ (it had an error in the URL for the HTML version of the FAQ)]. BIG NEWS: * The content of this document has been extensively updated. * An HTML version that is broken up by sections is now available at: http://www.cerfnet.com/~mpcline/On-Line-C++-FAQs/ Posting 1 of 4. The On-Line C++ FAQs (Frequently Asked Questions) Revised Apr 26, 1996 ============================================================================== COMMON PREFIX INFORMATION: AUTHOR: Marshall P. Cline, Ph.D., cline@parashift.com Paradigm Shift, Inc. / One Park St. / Norwood, NY 13668 315-353-6100 (voice) / 315-353-6110 (fax) COPYRIGHT: This document (the "On-Line C++ FAQs") is Copyright (C) 1991-96 Marshall P. Cline, Ph.D., cline@parashift.com. All rights reserved. Copying is permmitted only under designated situations (see section [1] for permissions). NO WARRANTY: THIS WORK IS PROVIDED ON AN "AS IS" BASIS. THE AUTHOR PROVIDES NO WARRANTY WHATSOEVER, EITHER EXPRESS OR IMPLIED, REGARDING THE WORK, INCLUDING WARRANTIES WITH RESPECT TO ITS MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. On-Line-C++-FAQs != C++-FAQs-Book: Note: This document (the "On-Line C++ FAQs") is not the same as the "C++ FAQs" book (e.g., the "C++ FAQs" book is five times larger than this on-line document). The "C++ FAQs" book is available in bookstores ("C++ FAQs" by Cline and Lomow, Addison-Wesley, 1995, ISBN 0-201-58958-3; see also http://heg-school.aw.com/cseng/authors/cline/FAQ/FAQ.html). ============================================================================== OVERVIEW OF ALL SECTIONS: 1. Copying permissions 2. On-line sites that distribute this document 3. "C++-FAQs-Book" versus "On-Line-C++-FAQs" 4. List of recent changes to this document 5. How to post to comp.lang.c++ (Read Before Posting!) 6. Managerial issues 7. Classes and objects 8. References 9. Inline functions 10. Constructors and destructors 11. Operator overloading 12. Friends 13. Input/output via and 14. Freestore management 15. Exceptions and error handling 16. Const correctness 17. Basics of inheritance 18. Inheritance and virtual functions 19. Inheritance and conformance 20. Inheritance and access rules 21. Inheritance and constructors/destructors 22. Private and protected inheritance 23. Abstraction 24. Style guidelines 25. Keys for Smalltalk programmers to learn C++ 26. Reference and value semantics 27. How to mix C and C++ 28. Pointers to member functions 29. Container classes and templates 30. Class libraries 31. Compiler dependencies 32. Miscellaneous technical issues 33. Miscellaneous environmental issues ============================================================================== SECTION [1]: Copying permissions [1.1] Can this document be copied legally? This document (the "On-Line C++ FAQs") is Copyright (C) 1991-96 Marshall P. Cline, Ph.D., cline@parashift.com. All rights reserved. However you are allowed to copy and/or distribute all or part of this document under the following conditions: * No changes are made to whatever portions are copied and/or distributed. * And the "Author," "Copyright," "No Warranty," and "On-Line-C++-FAQs != C++-FAQs-Book" sections are retained verbatim and are displayed conspicuously. ============================================================================== [1.2] What if more and/or different privileges are wanted than those outlined above? If you need other permissions that aren't covered by the above, please contact the author. I'm a very reasonable man... ============================================================================== SECTION [2]: On-line sites that distribute this document [2.1] Where can I download this on-line document in the USA? http://www.cerfnet.com/~mpcline/On-Line-C++FAQs/ is the official home for this document. All others are mirror copies that may or may not be up to date. Also, http://www.connobj.com/cpp/cppfaq.htm has this document as one large HTML file (i.e., not broken up into sections). ============================================================================== [2.2] Where can I download this on-line document in Europe? * http://www.cs.bham.ac.uk/~jdm/CPP/cppfaq.html * http://www.informatik.uni-konstanz.de/~kuehl/cpp/cppfaq.htm * ftp://rtfm.mit.edu/pub/usenet-by-group/comp.lang.c++/ ============================================================================== [2.3] Where can I download a Chinese translation of this on-line document? ftp://ftp.cis.nctu.edu.tw/Documents/News/comp.lang.c++/c-cppfaq.* contains a Chinese translation encoded in the "Big5" code ("Big5" is a 16-bit Chinese code used mostly in Taiwan). ============================================================================== SECTION [3]: "C++-FAQs-Book" versus "On-Line-C++-FAQs" [3.1] Is there a "C++ FAQs" book I can buy in a bookstore? Yes. "C++ FAQs" by Cline and Lomow, Addison-Wesley, 1995, ISBN 0-201-58958-3. ============================================================================== [3.2] Is this on-line document the same as the "C++ FAQs" book? No! This document is called the "On-Line C++ FAQs" document. However the "On-Line C++ FAQs" document is not the same as the "C++ FAQs" book. The "C++ FAQs" book ("C++ FAQs", Addison-Wesley, 1995; http://heg-school.aw.com/cseng/authors/cline/FAQ/FAQ.html) is five (5) times larger than this on-line document. ============================================================================== [3.3] How can I download a free copy of the "C++ FAQs" book? sneaker-net://your.local.bookstore/tech-section/ISBN=0-201-58958-3 In other words, the "C++ FAQs" book is available in bookstores ("C++ FAQs", Addison-Wesley, 1995; ISBN 0-201-58958-3). It is not available in any on-line forum. Note that you can get a peek at some excerpts from the "C++ FAQs" book via http://heg-school.aw.com/cseng/authors/cline/FAQ/FAQ.html ============================================================================== [3.4] Why would I spend good money on a book when I can download it for free? Because the book contains five times more material than this on-line document. Many people have asked about the relationship between the book ("C++ FAQs", ISBN 0-201-58958-3) and this on-line document. Some have wondered whether the posting is equivalent to the book. The "C++ FAQs" book is loosely based on the same concepts as this on-line document. However the "C++ FAQs" book is approximately five (5) times bigger than this on-line document. For example, the book's discussions are much more detailed than in the on-line document, and the variety of FAQs is much wider in the book. The book also includes thousands of cross references, external references, and index terms, as well as many programming examples. ============================================================================== SECTION [4]: List of recent changes to this document [4.1] What updates were made for the 6/96 release? * Updated everything * Transformed the source from raw text to HTML * Reorganized, reworded, expanded, added examples, etc, etc ============================================================================== [4.2] What updates were made for the 5/96 release? * Added two more FAQs on including C header files (currently FAQ 112 & 113) * Updated the FAQ on pure virtual functions (near FAQ-77) * Updated the FAQ on delete this (near FAQ-39) ============================================================================== [4.3] What updates were made for the 4/96 release? * Added European mirror site for the WWW addresses: http://www.informatik.uni-konstanz.de/~kuehl/cpp/cppfaq.htm ============================================================================== [4.4] What updates were made for the 3/96 release? * Added a FAQ on whether C++ is better than Ada (or Visual Basic or ...) * Added WWW and anonymous ftp addresses: http://www.connobj.com/cpp/cppfaq.htm ftp://rtfm.mit.edu/pub/usenet-by-group/comp.lang.c++/ * Added a new FAQ on heterogeneous containers * Modified the FAQs covering coding standards * Added an Acronyms section for things like ARM, C++PL2, etc * Updated the dynamic-typing FAQs to reflect dynamic_cast and typeid() * Updated the ftp address for C++2LaTeX * Added a new LaTeX macro for pretty-printing the name "C++" * Added a paragraph in the FAQ on mixing new and free, or malloc and delete * Corrected an error in the on-line location for the ANSI-C++ draft standard * Corrected a access-level error in FAQ 45 * Added a note to FAQ 129 * Fixed the "iostream vs stdio" FAQ * Fixed a typo in FAQ 111 * Corrected numerous typographical errors ============================================================================== [4.5] What updates were made for the 1/96 release? * Anonymous ftp from soe.clarkson.edu still does not work * No significant changes were made this month ============================================================================== [4.6] What updates were made for the 9/95 release? * Added FAQ 41 on using a variable for the first dimension of a multi-dimensional array * Added FAQ 123 on the code from "Numerical Recipes" * Added section 20 ("Libraries"). It's still pretty sparse, but it's a start * Fixed a bug in FAQ 30 (there was no variable i) * Added FAQ 124 on dynamic linking to avoid bloated executables * Added FAQ 32 on trying to "reopen" cin and cout in binary mode * Added the access info to get the ANSI/ISO Committee Draft via ftp (FAQ 7) ============================================================================== [4.7] What updates were made for the 7/95 release? * Minor stuff (but not change in FTP access, below) ============================================================================== [4.8] What updates were made for the 6/95 release? * Corrected the mailing address where the ANSI-C++ Draft can be ordered * Added a FAQ on floating point [Thanks to Phil Staite] * Added a FAQ on multidimensional arrays [Thanks to Doug Shapter] * Added a FAQ on interrupt service routines and pointers to member functions * Reorganized the FAQ on allocating all objects of a certain class via new ============================================================================== [4.9] What updates were made for the 5/95 release? * Minor cosmetic changes ============================================================================== [4.10] What updates were made for the 4/95 release? * Added a question on a common BC++ Windows issue * Fixed the ftp address for NIHCL * Added an explanation that "ARM" is short for "Annotated Reference Manual" ============================================================================== [4.11] What updates were made for the 3/95 release? * Added a question on delete this * Added two questions on iostreams and eof * Fixed the entry on "c-mode" and "cc-mode" in Gnu emacs ============================================================================== [4.12] What updates were made for the 1/95 release? * A Chinese version of this document has been produced; details below ============================================================================== [4.13] What updates were made for the 12/94 release? * Added a FAQ on STL (currently #115) * Added a FAQ on name mangling (currently #119) * Fixed typo in FAQ that compared composition with private inheritance * Corrected some spelling errors ============================================================================== [4.14] What updates were made for the 11/94 release? * Added differentiator between "C++ FAQs" book and "On-Line C++ FAQs" * Other cosmetic changes ============================================================================== [4.15] What updates were made for the 10/94 release? * Fixed a few typos ============================================================================== [4.16] What updates were made for the 9/94 release? * Minor cosmetic changes ============================================================================== [4.17] What updates were made for the 8/94 release? * Made it up-to-date with respect to typeid and dynamic_cast * Made it up-to-date with respect to mutable and const_cast * Rewrote most of the answers to provide general cleanup * The quotation marks are now "..." rather than `...' or ``...'' * Sample code lines start with a tab; no other lines starts with a tab * Everything was edited; minor modifications everywhere ============================================================================== [4.18] What updates were made before 8/94? * This document was originally written in 1991 * I have no record of the specific changes that were made until 8/94 ============================================================================== SECTION [5]: How to post to comp.lang.c++ (Read Before Posting!) [5.1] How can I find out about general netiquette so I don't embarrass myself? General netiquette questions are answered in the newsgroup news.announce.newusers. This newsgroup contains many must-read articles for new users. Here are three important hints: * Some people post a question, then say something like, "Please respond by email because I don't normally read this newsgroup." This is really bad netiquette, and it almost guarantees that no one will answer your question (or worse: the only people who answer your question will be those who know so little about the way things work that they don't realize your bad form, and their answer will therefore probably be wrong). If you don't have enough time for the newsgroup, don't expect the newsgroup to have enough time for you! * It is bad netiquette to post a question to a newsgroup if that question is already answered in the newsgroup's FAQ. You really should read the FAQ before posting. If you don't, you're implicitly saying that your time is more valuable than the time of hundreds and hundreds of others. Tres uncool. Read the FAQ first! * There's something called "cross posting." This lets you post a question to a big pile of newsgroups at once. Don't! Cross posting to a large collection of newsgroups is bad netiquette. You will get flamed. Instead you should post to the newsgroup (singular) that best fits your question (see next FAQ for how to select the "best" newsgroup). If you don't get an answer in the "right" newsgroup and feel you must post somewhere else, at least consider redirecting followups back to the appropriate newsgroup. ============================================================================== [5.2] Which newsgroup should I post my questions? Here's a list of some very active newsgroups, along with some sample topics that should give you an idea of the topics discussed there: * comp.lang.c++ * The main topic of comp.lang.c++ is supposed to be the C++ language itself * Examples: C++ code design, syntax, style * If you want to post a question regarding a particular operating system (e.g., Windows 3.x, Windows 95, UNIX, etc), please post it in an operating-system-specific newsgroup; do not post it in comp.lang.c++ * comp.lang.c++.moderated * A moderated variant of comp.lang.c++ * The moderator's job is to keep the signal-to-noise ratio higher than in comp.lang.c++ * comp.object * Mostly OO design issues, with less emphasis on OO programming) * That group's FAQ contains an excellent introduction to OO along with an overview of OO terms and concepts * comp.std.c++ * Discussion directly related to the evolving ANSI/ISO C++ standard * The evolving ANSI/ISO C++ standard is discussed below * comp.os.ms-windows.programmer.tools * This group is intended for discussions about the selection and use of tools for Windows software development * comp.os.ms-windows.programmer.misc * This group is for all other discussions about Windows software development * There's one FAQ list for all the comp.os.ms-windows.programmer.* groups * Sample topic: Accessing C++ classes in a DLL * Sample topic: A dialog as an MDI child window [with OWL] * Sample topic: Disabled menu choices become enabled [with MFC] * Sample topic: Using STRICT with windows.h * Sample topic: A programmer's bibliography * comp.os.msdos.programmer * Much of the traffic is about language products, chiefly from Borland and Microsoft * Note: The FAQ for this group is not available at rtfm.mit.edu; it is at ftp://oak.oakland.edu/pub/msdos/info and ftp://garbo.uwasa.fi/pc/doc-net * Sample topic: How can I read a character without [waiting for] the Enter key? * Sample topic: How can I read, create, change, or delete the volume label? * Sample topic: How do I configure a COM port and use it to transmit data? * Sample topic: How can a C program send control codes to my printer? * Sample topic: How can I find the Microsoft mouse position and button status? * Sample topic: How can I write a TSR (terminate-stay-resident) utility? * Sample topic: How can I contact [Borland, Microsoft]? * comp.os.msdos.programmer.turbovision * Borland's character-mode framework * omp.unix.programmer * Sample topic: How do I use popen() to open a process for reading and writing? * Sample topic: How do I sleep() in a C program for less than one second? * comp.unix.solaris * Covers SunOS 4.x and Solaris * Sample topic: Signal Primer * Sample topic: Waiting for Children to Exit * gnu.g++.help * Sample topic: Where can I find a demangler? * Sample topic: Getting gcc/g++ binaries for Solaris 2.x * Sample topic: What documentation exists for g++ 2.x? * gnu.g++.bug * Bug reports for g++; see the g++ docs * comp.lang.c * FAQ is posted monthly, and is maintained by Steve Summit, scs@eskimo.com * Sample topic: I'm confused. NULL is guaranteed to be 0, but the null pointer is not? * Sample topic: So what is meant by the "equivalence of pointers and arrays" in C? * Sample topic: Why doesn't printf("%d\n", i++ * i++); work? * Sample topic: How can I write a function that takes a variable number of arguments? [stdarg.h or varargs.h] * Sample topic: How do I declare an array of pointers to functions returning pointers to functions returning pointers to characters? * comp.graphics * Issues revolving around graphics programming * comp.sources.wanted * If you want some source code for something, post your request there * comp.programming * General programming issues ============================================================================== [5.3] How do I get the FAQs for a particular newsgroup? Let me count the ways... FAQs (Frequently Asked Questions lists) are available 24-hours a day via: * ftp or WWW: ftp://rtfm.mit.edu/pub/usenet/ * e-mail: send a message with the line "help" to mail-server@rtfm.mit.edu * usenet: many FAQs are available in the newsgroup news.answers Please, PLEASE do not send email to me! ============================================================================== [5.4] How do I post a question about code that doesn't work correctly? Here's some guidelines you should follow that will help people reading comp.lang.c++ help you with an answer to your programming problem. 1. Please read the previous FAQ to make sure that your question is about the C++ language and not a question about programming on your system (e.g., graphics, printers, devices, etc.) or using your compilation environment (e.g., "the IDE crashes when I...," "how do you turn off warnings about...," "how do I tell it to link my libraries"). If you want to know why your virtual CmOk() function isn't being called in your OWL program, your question is probably more appropriate in the Windows programming newsgroup. If you can write a small stand-alone program which exhibits the same undesired compiler error or behavior as your OWL program, by all means post here in comp.lang.c++ since C++ programmers using other systems could be of help. 2. Be descriptive in the subject line. "C++ problem" leaves a lot to the imagination. "Problem new'ing a multi-dimensional array" is good. Refrain from exclamation points, cries for HELPPP, and the once funny "SEX SEX SEX." If you think the problem is specific to your compiler, you might want to mention the compiler/version in the subject line. 3. Post code that is complete and compilable. It's extremely difficult to debug or reconstruct a program from a human language description. By "complete code" I mean that any types and functions used are declared, headers are #include'd, etc. Please strip the code down to the bare essentials. We don't need a program that does something useful at run-time, or even links. We just need to be able to reproduce the undesired compiler error (possibly on a different compiler). By "compilable code" I mean that it doesn't contain a bunch of uncommented ellipses or line numbers at the beginning of each line: 14: #include 15: class Foo { ... }; // This is annoying Try to organize the code into one linear program instead of making us cut out and create header files. Be very careful if you are typing the code into your article -- it's often difficult to tell whether something is a typo or the real cause of the problem. Try using your editor's cut and paste or "insert file" feature instead. 4. Mention what compiler, compiler version, and system you're using. I know, I just said that system-specific questions should go to a system-specific newsgroup, but compiler information is often very useful in diagnosing the problem: ("yeah, I remember Acme 1.2 having lots of problems in this area"). It also warns other users of that compiler about possible bugs. 5. Show us the exact compiler and linker options and libraries you used when building your program. 6. List the exact error message and where the error was given. "Virtual functions don't work" doesn't tell us whether its a compile-, link-, or run-time problem. If the problem is at run-time, give a good description of the behavior and any relevant information about your system setup. 7. Include a working e-mail address in your signature. If the address in given your article's "From:" line is not correct, please notify your system administrator. Until it is fixed, add a "Reply-To:" line to your headers that uses your correct e-mail address. 8. Please read the rest of this FAQ -- chances are your problem, or a closely related problem, is discussed here. Thank you and I hope these suggestions help you find a solution to your problem. ============================================================================== SECTION [6]: Managerial issues [6.1] What is OO? What is C++? Object-oriented techniques are the best way we know of to develop large, complex software applications and systems. C++ is an OO programming language. C++ can also be used as a traditional programming language (as "as a better C"). However if you use it "as a better C," don't expect to get the benefits of object-oriented programming. OO hype: the software industry is "failing" to meet demands for large, complex software systems. But this "failure" is actually due to our successes: our successes have propelled users to ask for more. Unfortunately we created a market hunger that the "structured" analysis, design and programming techniques couldn't satisfy. This required us to create a better paradigm. ============================================================================== [6.2] Is C++ better than Ada? (or Pascal, C, FORTRAN, Visual Basic, or any other language?) This question generates much much more heat than light. Please read the following before posting some variant of this question. In 99% of the cases, programming language selection is dominated by business considerations, not by technical considerations. Things that really end up mattering are things like availability of a programming environment for the development machine, availability of runtime environment(s) for the deployment machine(s), licensing/legal issues of the runtime and/or development environments, availability of trained developers, availability of consulting services, and corporate culture/politics. These business considerations generally play a much greater role than compile time performance, runtime performance, static vs. dynamic typing, static vs. dynamic binding, etc. Therefore anyone who argues in favor of one language over another in a purely technical manner (i.e., who ignores the dominant business issues) exposes themselves as a techie weenie, and deserves not to be heard. ============================================================================== [6.3] What are some features of C++? * Growth of C++: C++ is by far the most popular OO programming language. The number of C++ users is doubling at least once every year. If you're a manager, this means you will very likely have a wide selection of development tools, environments, and consulting services. If you're a programmer, this means that knowing C++ is an essential resume-stuffer (but you need to think in OO to make yourself really valuable; tons and tons and tons of people simply know the syntax of C++, but they think of it as a souped up C; those people need to learn OO). * Encapsulation: Hiding stuff allows you to change one chunk of a system without breaking other chunks. The chunks (called "classes" in OO-speak) are given safe interfaces. Users of a chunk use its interface only. The relatively volatile "implementation" of this interface is "encapsulated" ("put into a capsule") to prevent users from becoming reliant on the temporary, fickle decisions of the class builder. In C, this was done by making things static in a module, which prevented another module from accessing the static stuff. * Multiple instances: The typical C solution to encapsulation (see above) doesn't support multiple instances of the data (C doesn't directly support the tricks needed to make multiple instances of a module's static data). If multiple instances were needed in C, programmers typically used a struct. But unfortunately C structs don't support encapsulation). In C++, programmers can have both multiple instances and encapsulation via a class: the public part of a class contains the class's interface (normally these are a special kind of function called a "member function"), and the private part of a class contains the class's implementation (typically these are where the bits live). * Inline function calls: In straight C, you can achieve "encapsulated structs" by putting a void* in a struct, in which case the void* points to the real data, but users of the struct don't know how to interpret the stuff pointed to by the void*, which gave a form of encapsulation (obviously the access functions used pointer casts). This forfeits type safety, and also imposes a function call to access even trivial fields of the struct (if you allowed direct access to the struct's fields, the underlying data structure would be difficult to change since then anyone and everyone would be able to get direct access; i.e., they would know how to interpret the stuff pointed to by the void*). Function call overhead is small, but can add up. C++ classes allow function calls to be expanded inline, so you have: the (1) safety of encapsulation, (2) convenience of multiple instances, (3) speed of direct access. Furthermore the parameter types of these inline functions are checked by the compiler, an improvement over C's #define macros. * Overloading operators: C++ lets you overload the standard operators on a class, which lets users exploit their intuition (e.g., myString + yourString might do string concatenation, myDate++ might increment the date, z1 * z2 might multiply complex numbers z1 and z2, a[i] might access the i'th element of the "linked list" called a, etc). You can even have "smart pointers" that could "point" to a disk record or wherever (x = *p could "dereference" such a pointer, which could seek to the location on disk where p "points" and return the record). This allows users to program in the language of the problem domain rather than in the language of the machine. * Inheritance: We still have just scratched the surface. In fact, we haven't even gotten to the "object-oriented" part yet! Suppose you have a Stack data type with operations push(), pop(), etc. Suppose you want an InvertableStack, which is "just like" Stack except it also has an invert() operation. In C style, you'd have to either (1) modify the existing Stack module (trouble if Stack is being used by others), or (2) copy Stack into another file and text edit that file (results in lots of code duplication, another chance to break something tricky in the Stack part of InvertableStack, and twice as much code to maintain). C++ provides a much cleaner solution: inheritance. InvertableStack inherits everything from Stack, and InvertableStack adds the invert() operation. Done. Stack itself remains "closed" (untouched, unmodified), and InvertableStack doesn't duplicate the code for push(), pop(), etc. * Polymorphism and dynamic binding: The real power of OO isn't just inheritance, but is the ability to pass an InvertableStack around as if it actually were a Stack. This is "safe" since (in C++ at least) the is-a relation follows public inheritance (i.e., a InvertableStack is-a Stack that can also invert() itself). Polymorphism and dynamic binding are easiest to understand from an example, so here's a "classic": a graphical drawing package might deal with Circles, Squares, Rectangles, general Polygons, and Lines. All of these are Shapes. Most of the draw package's functions need a Shape parameter (as opposed to some particular kind of shape like Square). E.g., a pick_and_drag(Shape*) function might be called if a Shape is picked by a mouse, and the function might cause the Shape to get dragged across the screen and placed into a new location. Polymorphism and dynamic binding allow the code to work correctly even if the compiler knows only that the parameter is a Shape without knowing the exact kind of Shape it is. Furthermore suppose such a pick_and_drag(Shape*) function was compiled on Tuesday, and on Wednesday you decide to add the Hexagon shape. Strange as it sounds, pick_and_drag() will still work with a Hexagon, even though the Hexagon code didn't even exist when pick_and_drag() was compiled!! (it's not really "amazing" once you understand how the C++ compiler does it -- but it's still very convenient!) ============================================================================== [6.4] Who uses C++? Lots and lots of companies and government sites. Lots. Statistically, 5 people became new C++ programmers while you read the words of the previous FAQ. ============================================================================== [6.5] Are there any C++ standardization efforts underway? Yes; ANSI (American) and ISO (International) groups are working closely with each other. The ANSI-C++ committee is called "X3J16". The ISO C++ standards group is called "WG21". The major players in the ANSI/ISO C++ standards process includes just about everyone: AT&T, IBM, DEC, HP, Sun, MS, Borland, Zortech, Apple, OSF, etc ad nauseum. Dozens of people attend each meeting. People come from USA, UK, Japan, Germany, Sweden, Denmark, France, ... (all have "local" committees sending official representatives and conducting "local" meetings). ============================================================================== [6.6] Where can I get a copy of the latest ANSI/ISO-C++ draft standard? The ISO Committee Draft for C++ and the ANSI C++ Draft (the document that is going out for public review) is available from: * http://www.cygnus.com/~mrs/wp-draft You can also get Postscript and Adobe Acrobat versions from: * ftp://research.att.com/dist/c++std/WP * ftp://ftp.maths.warwick.ac.uk:/pub/c++/std/WP * ftp://ftpt.su.edu.au:/pub/C++/CommitteeDraft You can get HTML and ASCII versions: * ftp://ftp.cygnus.com/pub/g++ You can also get a paper copy from: * Lynn Barra * Ask for the latest version of "Draft Proposed American National Standard for Information Systems -- Programming Language C++" which is document number CD14882 * It is typically shipped 2-day FedEx within the continental US You can also order a paper copy via snail-mail: * X3 Secretariat 1250 Eye Street NW Suite 200 Washington, DC 20005 202-626-5738 * Ask for the latest version of "Draft Proposed American National Standard for Information Systems -- Programming Language C++" which is document number CD14882 * It is typically shipped 2-day FedEx within the continental US ============================================================================== [6.7] Is C++ backward compatible with ANSI-C? Almost. C++ is as close as possible to compatible with C, but no closer. In practice, the major difference is that C++ requires prototypes, and that f() declares a function that takes no parameters (in C, f() is the same as f(...)). There are some very subtle differences as well, like sizeof('x') is equal to sizeof(char) in C++ but is equal to sizeof(int) in C. Also, C++ puts structure "tags" in the same namespace as other names, whereas C requires an explicit struct (e.g., the typedef struct Fred Fred; technique still works, but is redundant in C++). ============================================================================== [6.8] How long does it take to learn C++? Companies like Paradigm Shift, Inc. (info@parashift.com) successfully teach standard industry "short courses," where we compress a university semester course into one 40 hour work week. But regardless of where you get your training, make sure the courses have a hands-on element, since most people learn best when they have projects to help the concepts "gel." It takes 6-12 months to become proficient in OO/C++. Less if the developers have easy access to a "local" body of experts, more if there isn't a "good" general purpose C++ class library available. To become one of these experts who can mentor others takes around 3 years. Some people never make it. You don't have a chance unless you are teachable and have personal drive. As a bare minimum on "teachability," you have to be able to admit when you've are wrong. As a bare minimum on "drive," you must be willing to put in some extra hours (it's a lot easier to learn some new facts than it is to change your paradigm [i.e., to change the way you think; to change your notion of goodness; to change your mental model of the world of technology]). ============================================================================== SECTION [7]: Classes and objects [7.1] What is a class? The fundamental building block of OO software. A class defines a data type, much like a struct would be in C. In a computer science sense, a type consists of both a set of states and a set of operations which transition between those states. Thus int is a type because it has both a set of states and it has operations like i + j or i++, etc. In exactly the same way, a class provides a set of (usually public) operations, and a set of (usually non-public) data bits representing the abstract values that instances of the type can have. Think of int as a class that has member functions called operator++, etc. Note: a C programmer can think of a class as a C struct whose members default to private. But if that's all you think of a class, then you probably need to experience a personal paradigm shift. ============================================================================== [7.2] What is an object? A region of storage with associated semantics. After the declaration int i; we say that "i is an object of type int." In OO/C++, "object" usually means "an instance of a class." Thus a class defines the behavior of possibly many objects (instances). ============================================================================== SECTION [8]: References [8.1] What is a reference? An alias (an alternate name) for an object. References are frequently used for pass-by-reference: void swap(int& i, int& j) { int tmp = i; i = j; j = tmp; } main() { int x, y; // ... swap(x,y); } Here i and j are aliases for main's x and y respectively. In other words, i is x -- not a pointer to x, nor a copy of x, but x itself. Anything you do to i gets done to x, and vice versa. OK. That's how you should think of references as a programmer. Now, at the risk of confusing you by giving you a different perspective, here's how references are implemented. Underneath it all, a reference i to object x is typically the machine address of the object x. But when the programmer says i++, the compiler generates code that increments x. In particular, the address bits that the compiler uses to find x are not changed. A C programmer will think of this as if you used the C style pass-by-pointer, with the syntactic variant of (1) moving the & from the caller into the callee, and (2) eliminating the *s. In other words, a C programmer will think of i as a macro for (*p), where p is a pointer to x (e.g., the compiler automatically dereferences the underlying pointer; i++ is changed to (*p)++; i = 7 is automatically changed to *p = 7). Important note: Even though a reference is often implemented using an address in the underlying assembly language, please do not think of a reference as a funny looking pointer to an object. A reference is the object. It is not a pointer to the object, nor a copy of the object. It is the object. ============================================================================== [8.2] What happens if you assign to a reference? You change the referent (the object to which the reference refers). Remember: the reference is the referent, so changing the reference changes the referent. In compiler writer lingo, a reference is an "lvalue" (something that can appear on the left hand side of an assignment operator). ============================================================================== [8.3] What happens if you return a reference? The function call can appear on the left hand side of an assignment operator. This ability may seem strange at first. For example, no one thinks the expression f() = 7 makes sense. Yet, if a is an object of class Array, most people think that a[i] = 7 makes sense even though a[i] is really just a function call in disguise (it calls Array::operator[](int), which is the subscript operator for class Array). class Array { public: int size() const; float& operator[] (int index); // ... }; main() { Array a; for (int i = 0; i < a.size(); ++i) a[i] = 7; // This line invokes Array::operator[](int) } ============================================================================== [8.4] How can you reseat a reference to make it refer to a different object? No way. You can't separate the reference from the referent. Unlike a pointer, once a reference is bound to an object, it can not be "reseated" to another object. The reference itself isn't an object (it has no identity; taking the address of a reference gives you the address of the referent; remember: the reference is its referent). ============================================================================== [8.5] When should I use references, and when should I use pointers? Use references when you can, and pointers when you have to. References are usually preferred over pointers whenever you don't need "reseating" (see previous FAQ). This usually means that references are most useful in a class's public interface. References typically appear on the skin of an object, and pointers on the inside. The exception to the above is where a function's parameter or return value needs a "sentinel" reference. This is usually best done by returning/taking a pointer, and giving the NULL pointer this special significance (references should always alias objects, not a dereferenced NULL pointer). Note: Old line C programmers sometimes don't like references since they provide reference semantics that isn't explicit in the caller's code. After some C++ experience, however, one quickly realizes this is a form of information hiding, which is an asset rather than a liability. E.g., programmers should write code in the language of the problem rather than the language of the machine. ============================================================================== SECTION [9]: Inline functions [9.1] What's the deal with inline functions? An inline function is a function whose code gets inserted into the caller's code stream. Like a #define macro, inline functions improve performance by avoiding the overhead of the call itself and (especially!) by the compiler being able to optimize through the call ("procedural integration"). ============================================================================== [9.2] How do you tell the compiler to make a non-member function inline? When you declare an inline function, it looks just like a normal function: void f(int i, char c); But when you define an inline function, you prepend the function's definition with the keyword inline, and you put the definition into a header file: inline void f(int i, char c) { // ... } Note: It's usually imperative that the function's definition (the part between the {...}) be placed in a header file. If you put the inline function's definition into a .cpp file, and if it is called from some other .cpp file, you'll get an "unresolved external" error from the linker. ============================================================================== [9.3] How do you tell the compiler to make a member function inline? When you declare an inline member function, it looks just like a normal member function: class Fred { public: void f(int i, char c); }; But when you define an inline member function, you prepend the member function's definition with the keyword inline, and you put the definition into a header file: inline void Fred::f(int i, char c) { // ... } It's usually imperative that the function's definition (the part between the {...}) be placed in a header file. If you put the inline function's definition into a .cpp file, and if it is called from some other .cpp file, you'll get an "unresolved external" error from the linker. ============================================================================== [9.4] Is there another way to tell the compiler to make a member function inline? Yep: define the member function in the class body itself: class Fred { public: void f(int i, char c) { // ... } }; Although this is easier on the person who writes the class, it's harder on all the readers since it mixes "what" a class does with "how" it does them. Because of this mixture, we normally prefer to define member functions outside the class body with the inline keyword (see previous FAQ). The insight that makes sense of this: in a reuse-oriented world, there will usually be many people who use your class, but there is only one person who builds it (yourself); therefore you should do things that favor the many rather than the few. ============================================================================== [9.5] Why should I use inline functions? Why not just use plain old #define macros? Because #define macros are evil. Unlike #define macros, inline functions avoid infamous macro errors since inline functions always evaluate every argument exactly once. In other words, invoking an inline function is semantically just like invoking a regular function, only faster: // A macro that returns the absolute value of i #define unsafe(i) \ ( (i) >= 0 ? (i) : -(i) ) // An inline function that returns the absolute value of i inline int safe(int i) { return i >= 0 ? i : -i; } int f(); void userCode(int x) { int ans; ans = unsafe(x++); // Error! x is incremented twice ans = unsafe(f()); // Danger! f() is called twice ans = safe(x++); // Correct! x is incremented once ans = safe(f()); // Correct! f() is called once } Also unlike macros, argument types are checked, and necessary conversions are performed correctly. Macros are bad for your health; don't use them unless you have to. ============================================================================== [9.6] Are inline functions guaranteed make your performance better? Nope. Beware that overuse of inline functions can cause code bloat, which can in turn have a negative performance impact in paging environments. ============================================================================== SECTION [10]: Constructors and destructors [10.1] What's the deal with constructors? Constructors build objects from dust. Constructors are like "init functions". They turn a pile of arbitrary bits into a living object. Minimally they initialize internally used fields. They may also allocate resources (memory, files, semaphores, sockets, etc). "ctor" is a typical abbreviation for constructor. ============================================================================== [10.2] How can I make a constructor call another constructor as a primitive? No way. Dragons be here: if you call another constructor, the compiler initializes a temporary local object; it does not initialize this object. You can combine both constructors by using a default parameter, or you can share their common code in a private init() member function. ============================================================================== [10.3] What's the deal with destructors? A destructor gives an object its last rites. Destructors are used to release any resources allocated by the object. E.g., class Lock might lock a semaphore, and the destructor will release that semaphore. The most common example is when the constructor uses new, and the destructor uses delete. Destructors are a "prepare to die" member function. They are often abbreviated "dtor". ============================================================================== SECTION [11]: Operator overloading [11.1] What's the deal with operator overloading? It allows you to provide an intuitive interface to users of your class. Operator overloading allows C/C++ operators to have user-defined meanings on user-defined types (classes). Overloaded operators are syntactic sugar for function calls: class Fred { public: // ... }; #if 0 // Without operator overloading: Fred add(Fred, Fred); Fred mul(Fred, Fred); Fred f(Fred a, Fred b, Fred c) { return add(add(mul(a,b), mul(b,c)), mul(c,a)); // Yuk... } #else // With operator overloading: Fred operator+ (Fred, Fred); Fred operator* (Fred, Fred); Fred f(Fred a, Fred b, Fred c) { return a*b + b*c + c*a; } #endif ============================================================================== [11.2] But operator overloading makes my class look ugly; isn't it supposed to make my code clearer? Operator overloading makes life easier for the users of your class, not for you! Consider the following example. Some people don't like the keyword operator or the somewhat funny syntax that goes with it in the body of the class itself: class Array { public: int& operator[] (unsigned i); // Some people don't like this syntax // ... }; inline int& Array::operator[] (unsigned i) // Some people don't like this syntax { // ... } But the operator overloading syntax isn't supposed to make life easier for you when you're writing your class. It's supposed to make life easier for the users of your class: main() { Array a; a[3] = 4; // User code should be obvious and easy to understand... } Remember: in a reuse-oriented world, there will usually be many people who use your class, but there is only one person who builds it (yourself); therefore you should do things that favor the many rather than the few. ============================================================================== [11.3] What operators can/cannot be overloaded? Most can be overloaded. The only C operators that can't be are . and ?: (and sizeof, which is technically an operator). C++ adds a few of its own operators, most of which can be overloaded except :: and .*. Here's an example of the subscript operator (it returns a reference). First without operator overloading: class Array { public: #if 0 int& elem(unsigned i) { if (i>99) error(); return data[i]; } #else int& operator[] (unsigned i) { if (i>99) error(); return data[i]; } #endif private: int data[100]; }; main() { Array a; #if 0 a.elem(10) = 42; a.elem(12) += a.elem(13); #else a[10] = 42; a[12] += a[13]; #endif } ============================================================================== [11.4] Can I create a ** operator for "to-the-power-of" operations? Nope. The names of, precedence of, associativity of, and arity of operators is fixed by the language. There is no ** operator in C++, so you cannot create one for a class type. If you're in doubt, consider that x ** y is the same as x * (*y) (in other words, the compiler assumes y is a pointer). Besides, operator overloading is just syntactic sugar for function calls. Although this particular syntactic sugar can be very sweet, it doesn't add anything fundamental. I suggest you overload pow(base,exponent) (a double precision version is in ). By the way, operator^ can work for to-the-power-of, except it has the wrong precedence and associativity. ============================================================================== Path: senator-bedfellow.mit.edu!bloom-beacon.mit.edu!news.kei.com!nntp.coast.net!howland.reston.ans.net!usc!news.cerf.net!nic.cerf.net!mpcline From: mpcline@nic.cerf.net (Marshall Cline) Newsgroups: comp.lang.c++ Subject: C++ FAQ: posting #2/4 [IGNORE EARLIER POSTING!] Followup-To: comp.lang.c++ Date: 26 Apr 1996 21:22:14 GMT Organization: Paradigm Shift, Inc (technology consulting) Lines: 1257 Sender: cline@parashift.com Distribution: world Expires: +1 month Message-ID: <4lreq6$33d@news.cerf.net> Reply-To: cline@parashift.com (Marshall Cline) NNTP-Posting-Host: nic.cerf.net Summary: Please read this before posting to comp.lang.c++ Archive-name: C++-faq/part2_4 [PLEASE NOTE: PLEASE IGNORE THE EARLIER POSTING OF THE FAQ (it had an error in the URL for the HTML version of the FAQ)]. BIG NEWS: * The content of this document has been extensively updated. * An HTML version that is broken up by sections is now available at: http://www.cerfnet.com/~mpcline/On-Line-C++-FAQs/ Posting 2 of 4. The On-Line C++ FAQs (Frequently Asked Questions) Revised Apr 26, 1996 ============================================================================== COMMON PREFIX INFORMATION: AUTHOR: Marshall P. Cline, Ph.D., cline@parashift.com Paradigm Shift, Inc. / One Park St. / Norwood, NY 13668 315-353-6100 (voice) / 315-353-6110 (fax) COPYRIGHT: This document (the "On-Line C++ FAQs") is Copyright (C) 1991-96 Marshall P. Cline, Ph.D., cline@parashift.com. All rights reserved. Copying is permmitted only under designated situations (see section [1] for permissions). NO WARRANTY: THIS WORK IS PROVIDED ON AN "AS IS" BASIS. THE AUTHOR PROVIDES NO WARRANTY WHATSOEVER, EITHER EXPRESS OR IMPLIED, REGARDING THE WORK, INCLUDING WARRANTIES WITH RESPECT TO ITS MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. On-Line-C++-FAQs != C++-FAQs-Book: Note: This document (the "On-Line C++ FAQs") is not the same as the "C++ FAQs" book (e.g., the "C++ FAQs" book is five times larger than this on-line document). The "C++ FAQs" book is available in bookstores ("C++ FAQs" by Cline and Lomow, Addison-Wesley, 1995, ISBN 0-201-58958-3; see also http://heg-school.aw.com/cseng/authors/cline/FAQ/FAQ.html). ============================================================================== OVERVIEW OF ALL SECTIONS: 1. Copying permissions 2. On-line sites that distribute this document 3. "C++-FAQs-Book" versus "On-Line-C++-FAQs" 4. List of recent changes to this document 5. How to post to comp.lang.c++ (Read Before Posting!) 6. Managerial issues 7. Classes and objects 8. References 9. Inline functions 10. Constructors and destructors 11. Operator overloading 12. Friends 13. Input/output via and 14. Freestore management 15. Exceptions and error handling 16. Const correctness 17. Basics of inheritance 18. Inheritance and virtual functions 19. Inheritance and conformance 20. Inheritance and access rules 21. Inheritance and constructors/destructors 22. Private and protected inheritance 23. Abstraction 24. Style guidelines 25. Keys for Smalltalk programmers to learn C++ 26. Reference and value semantics 27. How to mix C and C++ 28. Pointers to member functions 29. Container classes and templates 30. Class libraries 31. Compiler dependencies 32. Miscellaneous technical issues 33. Miscellaneous environmental issues ============================================================================== SECTION [12]: Friends [12.1] What is a friend? Something to allow your class to grant access to another class or function. Friends can be either functions or other classes. A class grants access privileges to its friends. Normally a developer has political and technical control over both the friend and member functions of a class (else you may need to get permission from the owner of the other pieces when you want to update your own class). ============================================================================== [12.2] Do friends violate encapsulation? If they're used properly, they actually enhance encapsulation. You often need to split a class in half when the two halves will have different numbers of instances or different lifetimes. In these cases, the two halves usually need direct access to each other (the two halves used to be in the same class, so you haven't increased the amount of code that needs direct access to a data structure; you've simply reshuffled the code into two classes instead of one). The safest way to implement this is to make the two halves friends of each other. If you use friends like just described, you'll keep private things private. People who don't understand this often make naive efforts to avoid using friendship in situations like the above, and often they actually destroy encapsulation. They either use public data (grotesque!), or they make the data accessible between the halves via public get() and set() member functions. Having a public get() and set() member function for a private datum is OK only when the private datum "makes sense" from outside the class (from a user's perspective). In many cases, these get()/set() member functions are almost as bad as public data: they hide (only) the name of the private datum, but they don't hide the existence of the private datum. Similarly, if you use friend functions as a syntactic variant of a class's public access functions, they don't violate encapsulation any more than a member function violates encapsulation. In other words, a class's friends don't violate the encapsulation barrier: along with the class's member functions, they are the encapsulation barrier. ============================================================================== [12.3] What are some advantages/disadvantages of using friend functions? They provide a degree of freedom in the interface design options. Member functions and friend functions are equally privileged (100% vested). The major difference is that a friend function is called like f(x), while a member function is called like x.f(). Thus the ability to choose between member functions (x.f()) and friend functions (f(x)) allows a designer to select the syntax that is deemed most readable, which lowers maintenance costs. The major disadvantage of friend functions is that they require an extra line of code when you want dynamic binding. To get the effect of a virtual friend, the friend function should call a hidden (usually protected:) virtual member function. For example: class Base { public: friend void f(Base& b); // ... protected: virtual void do_f(); // ... }; inline void f(Base& b) { b.do_f(); } class Derived : public Base { public: // ... protected: virtual void do_f(); // "Override" the behavior of f(Base& b) // ... }; void userCode(Base& b) { f(b); } The statement f(b) in userCode(Base&) will invoke b.do_f(), which is virtual. This means that Derived::do_f() will get control if b is actually a object of class Derived. Note that Derived overrides the behavior of the protected: virtual member function do_f(); it does not have its own variation of the friend function, f(Base&). ============================================================================== [12.4] What does it mean that "friendship is neither inherited nor transitive"? I may declare you as my friend, but that doesn't mean I necessarily trust either your kids or your friends. * I don't necessarily trust the kids of my friends. The privileges of friendship aren't inherited. Derived classes of a friend aren't necessarily friends. If class Fred declares that class Base is a friend, classes derived from Base don't have any automatic special access rights to Fred objects. * I don't necessarily trust the friends of my friends. The privileges of friendship aren't transitive. A friend of a friend isn't necessarily a friend. If class Fred declares class Wilma as a friend, and class Wilma declares class Betty as a friend, class Betty doesn't necessarily have any special access rights to Fred objects. ============================================================================== [12.5] Should my class declare a member function or a friend function? Use a member when you can, and a friend when you have to. Sometimes friends are syntactically better (e.g., in class Fred, friend functions allow the Fred parameter to be second, while members require it to be first). Another good use of friend functions are the binary infix arithmetic operators. E.g., aComplex + aComplex should be defined as a friend rather than a member if you want to allow aFloat + aComplex as well (member functions don't allow promotion of the left hand argument, since that would change the class of the object that is the recipient of the member function invocation). In other cases, choose a member function over a friend function. ============================================================================== SECTION [13]: Input/output via and [13.1] How can I provide printing for a class Fred? Provide a friend operator<<: class Fred { public: friend ostream& operator<< (ostream& o, const Fred& fred); // ... private: int i_; // Just for illustration }; ostream& operator<< (ostream& o, const Fred& fred) { return o << fred.i_; } We use a friend rather than a member since the Fred parameter is second rather than first. Input is similar. The syntax follows (note that the parameter is "Fred&", not "const Fred&"): class Fred { public: friend istream& operator>> (istream& i, Fred& fred); // ... private: int i_; // Just for illustration }; istream& operator>> (istream& i, Fred& fred) { return i >> fred.i_; } ============================================================================== [13.2] Why should I use instead of the traditional ? Increase type safety, reduce errors, improve performance, allow extensibility, and provide subclassability. printf() is arguably not broken, and scanf() is perhaps livable despite being error prone, however both are limited with respect to what C++ I/O can do. C++ I/O (using << and >>) is, relative to C (using printf() and scanf()): * Better type safety: With , the type of object being I/O'd is known statically by the compiler. In contrast, uses "%" fields to figure out the types dynamically. * Less error prone: With , there are no redundant "%" tokens that have to be consistent with the actual objects being I/O'd. Removing redundancy removes a class of errors. * Extensible: The C++ mechanism allows new user-defined types to be I/O'd without breaking existing code. Imagine the chaos if everyone was simultaneously adding new incompatible "%" fields to printf() and scanf()?!). * Subclassable: The C++ mechanism is built from real classes such as ostream and istream. Unlike 's FILE*, these are real classes and hence subclassable. This means you can have other user-defined things that look and act like streams, yet that do whatever strange and wonderful things you want. You automatically get to use the zillions of lines of I/O code written by users you don't even know, and they don't need to know about your "extended stream" class. ============================================================================== [13.3] Why does my input seem to process past the end of file? Because the eof state is not set until after a read is attempted past the end of file. That is, reading the last byte from a file does not set the eof state. For example, the following code has an off-by-one error with the count i: int i = 0; while (! cin.eof()) { // WRONG! cin >> x; ++i; // Work with x ... } What you really need is: int i = 0; while (cin >> x) { // RIGHT! ++i; // Work with x ... } ============================================================================== [13.4] Why is my program ignoring my input request after the first iteration? Because the numerical extractor leaves non-digits behind in the input buffer. If your code looks like this: char name[1000]; int age; for (;;) { cout << "Name: "; cin >> name; cout << "Age: "; cin >> age; } What you really want is: for (;;) { cout << "Name: "; cin >> name; cout << "Age: "; cin >> age; cin.ignore(INT_MAX, '\n'); } ============================================================================== [13.5] How can I "reopen" cin and cout in binary mode under DOS and/or OS/2? This is implementation dependent. Check with your compiler's documentation. For example, suppose you want to do binary I/O using cin and cout. Suppose further that your operating system (such as DOS or OS/2) insists on translating "\r\n" into "\n" on input from cin, and "\n" to "\r\n" on output to cout or cerr. Unfortunately there is no standard way to cause cin, cout, and/or cerr to be opened in binary mode. Closing the streams and attempting to reopen them in binary mode might have unexpected or undesirable results. On systems where it makes a difference, the implementation might provide a way to make them binary streams, but you would have to check the manuals to find out. ============================================================================== SECTION [14]: Freestore management [14.1] Does delete p delete the pointer p, or the pointed-to-data, *p? The pointed-to-data. The keyword should really be delete_the_thing_pointed_to_by. The same abuse of English occurs when freeing the memory pointed to by a pointer in C: free(p) really means free_the_stuff_pointed_to_by(p). ============================================================================== [14.2] Can I free() pointers allocated with new? Can I delete pointers allocated with malloc()? No! It is perfectly legal, moral, and wholesome to use malloc() and delete in the same program, or to use new and free() in the same program. But it is illegal, immoral, and despicable to call free() with a pointer allocated via new, or to call delete on a pointer allocated via malloc(). Beware! I occasionally get email from people telling me that it works OK for them on machine X and compiler Y. That does not make it right! Sometimes people say, "But I'm just working with an array of char." Nonetheless do not mix malloc() and delete on the same pointer, or new and free() on the same pointer! If you allocated via p = new char[n], you must use delete[] p; you must not use free(p). Or if you allocated via p = malloc(n), you must use free(p); you must not use delete[] p or delete p! Mixing these up could cause a catastrophic failure at runtime if the code was ported to a new machine, a new compiler, or even a new version of the same compiler. You have been warned. ============================================================================== [14.3] Why should I use new instead of trustworthy old malloc()? Constructors/destructors, type safety, overridability. * Constructors/destructors: unlike malloc(sizeof(Fred)), new Fred() calls Fred's constructor. Similarly, delete p calls *p's destructor. * Type safety: malloc() returns a void* which isn't type safe. new Fred() returns a pointer of the right type (a Fred*). * Overridability: new is an operator that can be overridden by a class, while malloc() is not overridable on a per-class basis. ============================================================================== [14.4] Why shouldn't I use realloc() on pointers allocated via new? To save you from disaster. When realloc() has to copy the allocation, it uses a bitwise copy operation, which will tear many C++ objects to shreds. C++ objects should be allowed to copy themselves. They use their own copy constructor or assignment operator. ============================================================================== [14.5] How do I allocate / unallocate an array of things? Use p = new T[n] and delete[] p: Fred* p = new Fred[100]; // ... delete[] p; Any time you allocate an array of objects via new (usually with the [n] in the new expression), you must use [] in the delete statement. This syntax is necessary because there is no syntactic difference between a pointer to a thing and a pointer to an array of things (something we inherited from C). ============================================================================== [14.6] What if I forget the [] when deleteing array allocated via new T[n]? All life comes to a catastrophic end. It is the programmer's --not the compiler's-- responsibility to get the connection between new T[n] and delete[] p correct. If you get it wrong, neither a compile-time nor a run-time error message will be generated by the compiler. Heap corruption is a likely result. Or worse. Your program will probably die. ============================================================================== [14.7] Can I drop the [] when deleteing array of some built-in type (char, int, etc)? No! Sometimes programmers think that the [] in the delete[] p only exists so the compiler will call the appropriate destructors for all elements in the array. Because of this reasoning, they assume that an array of some built-in type such as char or int can be deleted without the []. E.g., they assume the following is valid code: void userCode(int n) { char* p = new char[n]; // ... delete p; // <---- ERROR! Should be delete[] p ! } But the above code is wrong, and it can cause a disaster at runtime. In particular, the code that's called for delete p is operator delete(void*), but the code that's called for delete[] p is operator delete[](void*). The default behavior for the latter is to call the former, but users are allowed to replace the latter with a different behavior (in which case they would normally also replace the corresponding new code in operator new[](size_t)). If they replaced the delete[] code so it wasn't compatible with the delete code, and you called the wrong one (i.e., if you said delete p rather than delete[] p), you could end up with a disaster at runtime. ============================================================================== [14.8] Is it legal (and moral) for a member function to say delete this? As long as you're careful, it's OK for an object to commit suicide (delete this). Here's how I define "careful": 1. You must be absolutely 100% positive sure that this object was allocated via new (not by "new[]", nor by placement new, nor a local object on the stack, nor a global, nor a member of another object; but by plain ordinary new). 2. You must be absolutely 100% positive sure that your member function will be the last member function invoked on this object. 3. You must be absolutely 100% positive sure that the rest of your member function (after the delete this line) doesn't touch any piece of this object (including calling any other member functions or touching any data members). 4. You must be absolutely 100% positive sure that no one even touches the this pointer itself after the delete this line. In other words, you must not examine it, compare it with another pointer, compare it with NULL, print it, cast it, do anything with it. Naturally the usual caveats apply in cases where your this pointer is a pointer to a base class and the destructor isn't virtual. ============================================================================== [14.9] How do I allocate multidimensional arrays using new? There are many ways to do this, depending on how flexible you want the array sizing to be. On one extreme, if you know all the dimensions at compile-time, you can allocate multidimensional arrays statically (as in C): class Fred { /*...*/ }; void manipulateArray() { Fred matrix[10][20]; // Use matrix[i][j]... // No need for explicit deallocation } On the other extreme, if you want to allow the various slices of the matrix to have a different sizes, you can allocate everything off the freestore. For example, in the following function, nrows is the number of rows in the array (i.e., the valid row numbers are from 0 to nrows-1 inclusive), and array element ncols[r] is the number of columns in row r (where r in the range 0 to nrows-1 inclusive): void manipulateArray(unsigned nrows, unsigned ncols[]) { Fred** matrix = new Fred*[nrows]; for (unsigned r = 0; r < nrows; ++r) matrix[r] = new Fred[ ncols[r] ]; // ... // Deletion is the opposite of allocation: for (r = nrows; r > 0; --r) delete[] matrix[r-1]; delete[] matrix; } Note the funny use of matrix[r-1] in the deletion process. This prevents wrap-around of the unsigned value when r goes one step past zero. ============================================================================== [14.10] Does C++ have arrays whose length can be specified at run-time? Yes, in the sense that STL has a vector template that provides this behavior. See on "STL" in the "Libraries" section. No, in the sense that built-in array types need to have their length specified at compile time. Yes, in the sense that even built-in array types can specify the first index bounds at run-time. E.g., comparing with the previous FAQ, if you only need the first array dimension to vary then you can just ask new for an array of arrays, rather than an array of pointers to arrays: const unsigned ncols = 100; // ncols = number of columns in the array class Fred { /*...*/ }; void manipulateArray(unsigned nrows) // nrows = number of rows in the array { Fred (*matrix)[ncols] = new Fred[nrows][ncols]; // ... delete[] matrix; } You can't do this if you need anything other than the first dimension of the array to change at run-time. ============================================================================== [14.11] How can I ensure objects of my class are always created via new rather than as locals or global/static objects? Make sure the class's constructors are private:, and define friend or static functions that return a pointer to the objects created via new (make the constructors protected: if you want to allow derived classes). class Fred { public: static Fred* create() { return new Fred(); } static Fred* create(int i) { return new Fred(i); } static Fred* create(const Fred& fred) { return new Fred(fred); } virtual ~Fred(); private: // Ctors are private; only want to allow dynamically allocated Fred's Fred(); Fred(int i); Fred(const Fred& fred); }; main() { Fred* p = Fred::create(5); // ... delete p; } ============================================================================== SECTION [15]: Exceptions and error handling [15.1] How can I handle a constructor that fails? Throw an exception. Constructors don't have a return type, so it's not possible to use error codes. The best way to signal constructor failure is therefore to throw an exception. If you don't have or won't use exceptions, here's a work-around. If a constructor fails, the constructor can put the object into a "zombie" state. Do this by setting an internal status bit so the object acts sort of like its dead even though it is technically still alive. Then add a query ("inspector") member function to check this "zombie" bit so users of your class can find out if their object is truly alive, or if it's a zombie (i.e., a "living dead" object). Also you'll probably want to have your other member functions check this zombie bit, and, if the object isn't really alive, do a no-op (or perhaps something more obnoxious such as abort()). This is really ugly, but it's the best you can do if you can't (or don't want to) use exceptions. ============================================================================== [15.2] How should I handle resources if my constructors may throw exceptions? Every data member inside your object should clean up its own mess. If a constructor throws an exception, the object's destructor is not run. If your object has already done something that needs to be undone (such as allocating some memory, opening a file, or locking a semaphore), this "stuff that needs to be undone" must be remembered by a data member inside the object. For example, rather than allocating memory into a raw Fred* data member, put the allocated memory into a "smart pointer" member object, and the destructor of this smart pointer will delete the Fred object when the smart pointer dies. ============================================================================== SECTION [16]: Const correctness [16.1] What is "const correctness"? A good thing. It means using the keyword const to ensure const objects don't get mutated. For example, if you wanted to create a function f() that accepted a String, plus you want to promise callers not to change the caller's String that gets passed to f(), you can have f() receive its String parameter . . . * void f(String s); // Pass by value * void f(const String& s); // Pass by reference-to-const * void f(const String* sptr); // Pass by pointer-to-const Attempted changes to the caller's String within any of these functions would be flagged by the compiler as an error at compile-time. Neither run-time space nor speed is degraded. On the other hand, if you wanted to create a function g() that But you cannot have f() receive its String parameter . . . As an opposite example, if you wanted to create a function g() that accepted a String, but you want to let callers know that g() might change the caller's String object, you can have g() receive its String parameter . . . * void g(String& s); // Pass by reference-to-non-const * void g(String* sptr); // Pass by pointer-to-non-const ============================================================================== [16.2] How is "const correctness" related to ordinary type safety? Declaring the const-ness of a parameter is just another form of type safety. It is almost as if a const String, for example, is a different class than an ordinary String, since the const variant is missing the various mutative operations in the non-const variant (e.g., you can imagine that a const String simply doesn't have an assignment operator). If you find ordinary type safety helps you get systems correct (it does; especially in large systems), you'll find const correctness helps also. ============================================================================== [16.3] Should I try to get things const correct "sooner" or "later"? At the very, very, very beginning. Back-patching const correctness results in a snowball effect: every const you add "over here" requires four more to be added "over there." ============================================================================== [16.4] What is a "const member function"? A member function that inspects (rather than mutates) its object. A const member function is indicated by a const suffix just after the member function's parameter list. Member functions with a const suffix are called "const member functions" or "inspectors." Member functions without a const suffix are called "non-const member functions" or "mutators." class Fred { public: void inspect() const; // This member promises NOT to change *this void mutate(); // This member function might change *this }; void userCode(Fred& changeable, const Fred& unchangeable) { changeable.inspect(); // OK: doesn't change a changeable object changeable.mutate(); // OK: changes a changeable object unchangeable.inspect(); // OK: doesn't change an unchangeable object unchangeable.mutate(); // ERROR: attempt to change unchangeable object } The error in unchangeable.mutate() is caught at compile time. There is no runtime space or speed penalty for const. The trailing const on inspect() member function means that the abstract (client-visible) state of the object isn't going to change. This is slightly different from promising that the "raw bits" of the object's struct aren't going to change. C++ compilers aren't allowed to take the "bitwise" interpretation unless they can solve the aliasing problem, which normally can't be solved (i.e., a non-const alias could exist which could modify the state of the object). Another (important) insight from this aliasing issue: pointing at an object with a const pointer doesn't guarantee that the object won't change; it promises only that the object won't change via that pointer). ============================================================================== [16.5] What do I do if I want to update an "invisible" data member inside a const member function? Use mutable, or use const_cast. A small percentage of inspectors need to make innocuous changes to data members (e.g., a Set object might want to cache its last lookup in hopes of improving the performance of its next lookup). By saying the changes are "innocuous," I mean that the changes wouldn't be visible from outside the object's interface (otherwise the member function would be a mutator rather than an inspector). When this happens, the data member which will be modified should be marked as mutable (put the mutable keyword just before the data member's declaration; i.e., in the same place where you could put const). This tells the compiler that the data member is allowed to change during a const member function. If your compiler doesn't support the mutable keyword, you can cast away the const'ness of this via the const_cast keyword. E.g., in Set::lookup() const, you might say, Set* self = const_cast(this); After this line, self will have the same bits as this (e.g., self == this), but self is a Set* rather than a const Set*. Therefore you can use self to modify the object pointed to by this. ============================================================================== [16.6] Does const_cast mean lost optimization opportunities? In theory, yes; in practice, no. Even if the language outlawed const_cast, the only way to avoid flushing the register cache across a const member function call would be to solve the aliasing problem (i.e., to ensure that there are no non-const pointers that point to the object). This can happen only in rare cases (when the object is constructed in the scope of the const member function invocation, and when all the non-const member function invocations between the object's construction and the const member function invocation are statically bound, and when every one of these invocations is also inlined, and when the constructor itself is inlined, and when any member functions the constructor calls are inline). ============================================================================== SECTION [17]: Basics of inheritance [17.1] Is inheritance important to C++? Yep. Inheritance is what separates abstract data type (ADT) programming from OO programming. ============================================================================== [17.2] When would I use inheritance? As a specification device. Human beings abstract things on two dimensions: part-of and kind-of. A Ford Taurus is-a-kind-of-a Car, and a Ford Taurus has-a Engine, Tires, etc. The part-of hierarchy has been a part of software since the ADT style became relevant; inheritance adds "the other" major dimension of decomposition. ============================================================================== [17.3] How do you express inheritance in C++? By the : public syntax: class Car : public Vehicle { public: // ... }; We state the above relationship in several ways: * Car is "a kind of a" Vehicle * Car is "derived from" Vehicle * Car is "a specialized" Vehicle * Car is the "subclass" of Vehicle * Vehicle is the "base class" of Car * Vehicle is the "superclass" of Car (this not as common in the C++ community) (Note: this FAQ has to do with public inheritance; private and protected inheritance are different; see below.) ============================================================================== [17.4] Is it OK to convert a pointer from a derived class to its base class? Yes. An object of a derived class is a kind of the base class. Therefore the conversion from a derived class pointer to a base class pointer is perfectly safe, and happens all the time. For example, if I am pointing at a car, I am in fact pointing at a vehicle, so converting a Car* to a Vehicle* is perfectly safe and normal: void f(Vehicle* v); void g(Car* c) { f(c); } // Perfectly safe; no cast (Note: this FAQ has to do with public inheritance; private and protected inheritance are different; see below.) ============================================================================== [17.5] Derived* --> Base* works OK; why doesn't Derived** --> Base** work? C++ allows a Derived* to be converted to a Base*, since a Derived object is a kind of a Base object. However trying to convert a Derived** to a Base** is flagged as an error. Although this error may not be obvious, it is nonetheless a good thing. For example, if you could convert a Car** to a Vehicle**, and if you could similarly convert a NuclearSubmarine** to a Vehicle**, you could assign those two pointers and end up making a Car* point at a NuclearSubmarine: class Vehicle { /*...*/ }; class Car : public Vehicle { /*...*/ }; class NuclearSubmarine : public Vehicle { /*...*/ }; main() { Car car; Car* carPtr = &car; Car** carPtrPtr = &carPtr; Vehicle** vehiclePtrPtr = carPtrPtr; // This is an error in C++ Vehicle* vehiclePtr = *vehiclePtrPtr; NuclearSubmarine sub; NuclearSubmarine* subPtr = ⊂ vehiclePtr = subPtr; // This last line would have caused carPtr to point to sub ! } In other words, if the Derived** --> Base** conversion was allowed, the Base** could be dereferenced (yielding a Base*), and the Base* could be made to point to an object of a different derived class, which could cause serious problems for national security (who knows what would happen if you invoked the openGasCap() member function on what you thought was a Car, but in reality it was a NuclearSubmarine!!).. ============================================================================== [17.6] Is a parking-lot-of-Car a kind-of parking-lot-of-Vehicle? Nope. I know it sounds strange, but it's true. You can think of this as a direct consequence of the previous FAQ, or you can reason it this way: if the kind-of relationship were valid, then someone could point a parking-lot-of-Vehicle pointer at a parking-lot-of-Car. But parking-lot-of-Vehicle has a addNewVehicleToParkingLot(Vehicle&) member function which can add any Vehicle object to the parking lot. This would allow you to park a NuclearSubmarine in a parking-lot-of-Car. Certainly it would be surprising if someone removed what they thought was a Car from the parking-lot-of-Car, only to find that it is actually a NuclearSubmarine. Another way to say this truth: a container of Thing is not a kind-of container of Anything even if a Thing is a kind-of an Anything. Swallow hard; it's true. You don't have to like it. But you do have to accept it. One last example which we use in our OO/C++ training courses: "A Bag-of-Apple is not a kind-of Bag-of-Fruit." If a Bag-of-Apple could be passed as a Bag-of-Fruit, someone could put a Banana into the Bag, even though it is supposed to only contain Apples! ============================================================================== [17.7] Is an array of Derived a kind-of array of Base? Nope. This is a corollary of the previous FAQ. Unfortunately this one can get you into a lot of hot water. Consider this: class Base { public: virtual void f(); // 1 }; class Derived : public Base { public: // ... private: int i_; // 2 }; void userCode(Base* arrayOfBase) { arrayOfBase[1].f(); // 3 } main() { Derived arrayOfDerived[10]; // 4 f(arrayOfDerived); // 5 } The compiler thinks this is perfectly type-safe. Line 5 converts a Derived* to a Base*. But in reality it is horrendously evil: since Derived is larger than Base, the pointer arithmetic done on line 3 is incorrect: the compiler uses sizeof(Base) when computing the address for arrayOfBase[1], yet the array is an array of Derived, which means the address computed on line 3 (and the subsequent invocation of member function f()) isn't even at the beginning of any object! It's smack in the middle of a Derived object. Assuming your compiler uses the usual approach to virtual functions, this will reinterpret the int i_ of the first Derived as if it pointed to a virtual table, it will follow that "pointer" (which at this point means we're digging stuff out of a random memory location), and grab one of the first few words of memory at that location and interpret them as if they were the address of a C++ member function, then load that (random memory location) into the instruction pointer and begin grabbing machine instructions from that memory location. The chances of this crashing are very high. The root problem is that C++ can't distinguish between a pointer-to-a-thing and a pointer-to-an-array-of-things. Naturally C++ "inherited" this feature from C. NOTE: If we had used an array-like class (e.g., STL's vector) instead of using a raw array, this problem would have been properly trapped as an error at compile time rather than a run-time disaster. ============================================================================== [17.8] Does array-of-Derived is-not-a-kind-of array-of-Base mean arrays are bad? Yes, arrays are evil. (only half kidding). Seriously, arrays are very closely related to pointers, and pointers are notoriously difficult to deal with. But if you have a complete grasp of why the above few FAQs were a problem from a design perspective (e.g., if you really know why a container of Thing is not a kind-of container of Anything), and if you think everyone else who will be maintaining your code also has a full grasp on these OO design truths, then you should feel free to use arrays. But if you're like most people, you should use a template container class such as STL's vector rather than raw arrays. ============================================================================== SECTION [18]: Inheritance and virtual functions [18.1] What is a "virtual member function"? A virtual function allows derived classes to replace the implementation provided by the base class. The compiler ensures the replacement is always called whenever the object in question is actually of the derived class, even if the object is accessed by a base pointer rather than a derived pointer. This allows algorithms in the base class to be replaced in the derived class, even if users don't know about the derived class. The derived class can either fully replace ("override") the base class member function, or the derived class can partially replace ("augment") the base class member function. The latter is accomplished by having the derived class member function call the base class member function, if desired. ============================================================================== [18.2] How can C++ achieve dynamic binding yet also static typing? When you have a pointer to an object, the object may actually be of a class that is derived from the class of the pointer (e.g., a Vehicle* that is actually pointing to a Car object). Thus there are two types: the (static) type of the pointer (Vehicle, in this case), and the (dynamic) type of the pointed-to object (Car, in this case). "Static typing" means that the legality of a member function invocation is checked at the earliest possible moment: by the compiler at compile time. The compiler uses the static type of the pointer to determine whether the member function invocation is legal. If the type of the pointer can handle the member function, certainly the pointed-to object can handle it as well. E.g., if Vehicle has a certain member function, certainly Car also has that member function since Car is a kind-of Vehicle. "Dynamic binding" means that the address of the code in a member function invocation is determined at the last possible moment: based on the dynamic type of the object at run time. It is called "dynamic binding" because the binding to the code that actually gets called is accomplished dynamically (at run time). ============================================================================== [18.3] Should a derived class replace ("override") a non-virtual function from a base class? It's legal, but it ain't moral. Experienced C++ programmers will sometimes redefine a non-virtual function (e.g., the derived class implementation might make better use of the derived class's resources for efficiency), or to get around the hiding rule (see below). However the client-visible effects must be identical, since non-virtual functions are dispatched based on the static type of the pointer/reference rather than the dynamic type of the pointed-to/referenced object. ============================================================================== [18.4] What's the meaning of, Warning: Derived::f(int) hides Base::f(float)? It means you're going to die. Here's the mess you're in: if Derived declares a member function named f(), and Base declares a member function named f() with a different signature (e.g., different parameter types and/or constness), then the Base f() is "hidden" rather than "overloaded" or "overridden" (even if the Base f() is virtual). Here's how you get out of the mess: Derived must redefine the Base member function(s) that are hidden (even if they are non-virtual). Normally this re-definition merely calls the appropriate Base member function. E.g., class Base { public: void f(int); }; class Derived : public Base { public: void f(double); void f(int i) { Base::f(i); } // The redefinition merely calls Base::f(int) }; ============================================================================== SECTION [19]: Inheritance and conformance [19.1] Should I hide member functions that were public in my base class? Never, never, never do this. Never. Never! Attempting to hide (eliminate, revoke, privatize) inherited public member functions is an all-too-common design error. It usually stems from muddy thinking. (Note: this FAQ has to do with public inheritance; private and protected inheritance are different; see below.) ============================================================================== [19.2] Is a Circle a kind-of an Ellipse? Not if Ellipse promises to be able to change its size asymmetrically. For example, suppose Ellipse has a setSize(x,y) member function, and suppose this member function promises the Ellipse's width() will be x, and its height() will be y. In this case, Circle can't be a kind-of Ellipse. Simply put, if Ellipse can do something Circle can't, then Circle can't be a kind of Ellipse. This leaves two potential (valid) relationships between Circle and Ellipse: * Make Circle and Ellipse completely unrelated classes * Derive Circle and Ellipse from a base class representing "Ellipses that can't necessarily perform an unequal-setSize() operation" In the first case, Ellipse could be derived from class AsymmetricShape, and setSize(x,y) could be introduced in AsymmetricShape. However Circle could be derived from SymmetricShape which has a setSize(size) member function. In the second case, class Oval could only have setSize(size) which sets both the width() and the height() to size. Ellipse and Circle could both inherit from Oval. Ellipse --but not Circle-- could add the setSize(x,y) operation (see the "hiding rule" for a caveat if the same member function name setSize() is used for both operations). (Note: this FAQ has to do with public inheritance; private and protected inheritance are different; see below.) ============================================================================== [19.3] Are there other options to the "Circle is/isnot kind-of Ellipse" dilemma? If you claim that all Ellipses can be squashed asymmetrically, and you claim that Circle is a kind-of Ellipse, and you claim that Circle can't be squashed asymmetrically, clearly you've got to adjust (revoke, actually) one of your claims. Thus you've either got to get rid of Ellipse::setSize(x,y), get rid of the inheritance relationship between Circle and Ellipse, or admit that your Circles aren't necessarily circular. Here are the two most common traps new OO/C++ programmers regularly fall into. They attempt to use coding hacks to cover up a broken design (they redefine Circle::setSize(x,y) to throw an exception, call abort(), choose the average of the two parameters, or to be a no-op). Unfortunately all these hacks will surprise users, since users are expecting width() == x and height() == y. The one thing you must not do is surprise your users. If it is important to you to retain the "Circle is a kind-of Ellipse" inheritance relationship, you can weaken the promise made by Ellipse's setSize(x,y). E.g., you could change the promise to, "This member function might set width() to x and/or it might set height() to y, or it might do nothing". Unfortunately this dilutes the contract into dribble, since the user can't rely on any meaningful behavior. The whole hierarchy therefore begins to be worthless (it's hard to convince someone to use an object if you have to shrug your shoulders when asked what the object does for them). (Note: this FAQ has to do with public inheritance; private and protected inheritance are different; see below.) ============================================================================== [19.4] But I have a Ph.D. in Mathematics, and I'm sure a Circle is a kind of an Ellipse! Does this mean Marshall Cline is stupid? Or that C++ is stupid? Or that OO is stupid? Actually, it doesn't mean any of these things. The sad reality is that it means your intuition is wrong. Look, I have received and answered dozens of passionate email messages about this subject. I have taught it hundreds of times to thousands of software professionals all over the place. I know it goes against your intuition. But trust me; your intuition is wrong. The real problem is your intuitive notion of "kind of" doesn't match the OO notion of proper inheritance (technically called "subtyping"). The bottom line is that the derived class objects must be substitutable for the base class objects. In the case of Circle/Ellipse, the setSize(x,y) member function violates this substitutability. You have three choices: [1] remove the setSize(x,y) member function from Ellipse (thus breaking existing code that calls the setSize(x,y) member function), [2] allow a Circle to have a different height than width (an asymmetrical circle; hmmm), or [3] drop the inheritance relationship. Sorry, but there simply are no other choices. Note that some people mention the option of deriving both Circle and Ellipse from a third common base class, but that's just a variant of option [3] above. Another way to say this is that you have to either make the base class weaker (in this case braindamage Ellipse to the point that you can't set its width and height to different values), or make the derived class stronger (in this case empower a Circle with the ability to be both symmetric and, ahem, asymmetric). When neither of these is very satisfying (such as in the Circle/Ellipse case), one normally simply removes the inheritance relationship. If the inheritance relationship simply has to exist, you may need to remove the mutator member functions (setHeight(y), setWidth(x), and setSize(x,y)) from the base class. (Note: this FAQ has to do with public inheritance; private and protected inheritance are different; see below.) ============================================================================== [19.5] But my problem doesn't have anything to do with circles and ellipses, so what good is that silly example to me? Ahhh, there's the rub. You think the Circle/Ellipse example is just a silly example. But in reality, your problem is an isomorphism to that example. I don't care what your inheritance problem is, but all (yes all) bad inheritances boil down to the Circle-is-not-a-kind-of-Ellipse example. Here's why: Bad inheritances always have a base class with an extra capability (often an extra member function or two; sometimes an extra promise made by one or a combination of member functions) that a derived class can't satisfy. You've either got to make the base class weaker, make the derived class stronger, or eliminate the proposed inheritance relationship. I've seen lots and lots and lots of these bad inheritance proposals, and believe me, they all boil down to the Circle/Ellipse example. Therefore, if you truly understand the Circle/Ellipse example, you'll be able to recognize bad inheritance everywhere. If you don't understand what's going on with the Circle/Ellipse problem, the chances are high that you'll make some very serious and very expensive inheritance mistakes. Sad but true. (Note: this FAQ has to do with public inheritance; private and protected inheritance are different; see below.) ============================================================================== SECTION [20]: Inheritance and access rules [20.1] What's the difference between public:, private:, and protected:? private: is discussed in the previous section, and public: means "anyone can access it." The third option, protected:, makes a member (either data member or member function) accessible to subclasses. ============================================================================== [20.2] Why can't my derived class access private things from my base class? To protect you from future changes to the base class. Derived classes do not get access to private members of a base class. This effectively "seals off" the derived class from any changes made to the private members of the base class. ============================================================================== [20.3] How can I protect subclasses from breaking when I change internal parts? A class has two distinct interfaces for two distinct sets of clients: * It has a public: interface that serves unrelated classes * It has a protected: interface that serves derived classes Unless you expect all your subclasses to be built by your own team, you should consider making your base class's bits be private:, and use protected: inline access functions by which derived classes will access the private data in the base class. This way the private bits can change, but the derived class's code won't break unless you change the protected access functions. ============================================================================== SECTION [21]: Inheritance and constructors/destructors [21.1] When my base class's constructor calls a virtual function, why doesn't my derived class's override of that virtual function get invoked? During the class Base's constructor, the object isn't yet a Derived, so if Base::Base() calls a virtual function virt(), the Base::virt() will be invoked, even if Derived::virt() exists. Similarly, during Base's destructor, the object is no longer a Derived, so when Base::~Base() calls virt(), Base::virt() gets control, not the Derived::virt() override. You'll quickly see the wisdom of this approach when you imagine the disaster if Derived::virt() touched a member object from class Derived. ============================================================================== [21.2] Does a derived class destructor need to explicitly call the base destructor? No. Never explicitly call a destructor (where "never" means "rarely"). A derived class's destructor (whether or not you explicitly define one) automatically invokes the destructors for member objects and base class subobjects. Member objects are destroyed in the reverse order they appear within the class, then base class subobjects are destroyed in the reverse order that they appear in the class's list of base classes. You should explicitly call a destructor only in esoteric situations, such as when destroying an object created by the "placement new operator." ============================================================================== Path: senator-bedfellow.mit.edu!bloom-beacon.mit.edu!paperboy.osf.org!bone.think.com!blanket.mitre.org!news.mathworks.com!newsfeed.internetmci.com!panix!news.columbia.edu!news.new-york.net!wlbr!news.cerf.net!nic.cerf.net!mpcline From: mpcline@nic.cerf.net (Marshall Cline) Newsgroups: comp.lang.c++ Subject: C++ FAQ: posting #3/4 [IGNORE EARLIER POSTING!] Followup-To: comp.lang.c++ Date: 26 Apr 1996 21:22:27 GMT Organization: Paradigm Shift, Inc (technology consulting) Lines: 1058 Sender: cline@parashift.com Distribution: world Expires: +1 month Message-ID: <4lreqj$33f@news.cerf.net> Reply-To: cline@parashift.com (Marshall Cline) NNTP-Posting-Host: nic.cerf.net Summary: Please read this before posting to comp.lang.c++ Archive-name: C++-faq/part3_4 [PLEASE NOTE: PLEASE IGNORE THE EARLIER POSTING OF THE FAQ (it had an error in the URL for the HTML version of the FAQ)]. BIG NEWS: * The content of this document has been extensively updated. * An HTML version that is broken up by sections is now available at: http://www.cerfnet.com/~mpcline/On-Line-C++-FAQs/ Posting 3 of 4. The On-Line C++ FAQs (Frequently Asked Questions) Revised Apr 26, 1996 ============================================================================== COMMON PREFIX INFORMATION: AUTHOR: Marshall P. Cline, Ph.D., cline@parashift.com Paradigm Shift, Inc. / One Park St. / Norwood, NY 13668 315-353-6100 (voice) / 315-353-6110 (fax) COPYRIGHT: This document (the "On-Line C++ FAQs") is Copyright (C) 1991-96 Marshall P. Cline, Ph.D., cline@parashift.com. All rights reserved. Copying is permmitted only under designated situations (see section [1] for permissions). NO WARRANTY: THIS WORK IS PROVIDED ON AN "AS IS" BASIS. THE AUTHOR PROVIDES NO WARRANTY WHATSOEVER, EITHER EXPRESS OR IMPLIED, REGARDING THE WORK, INCLUDING WARRANTIES WITH RESPECT TO ITS MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. On-Line-C++-FAQs != C++-FAQs-Book: Note: This document (the "On-Line C++ FAQs") is not the same as the "C++ FAQs" book (e.g., the "C++ FAQs" book is five times larger than this on-line document). The "C++ FAQs" book is available in bookstores ("C++ FAQs" by Cline and Lomow, Addison-Wesley, 1995, ISBN 0-201-58958-3; see also http://heg-school.aw.com/cseng/authors/cline/FAQ/FAQ.html). ============================================================================== OVERVIEW OF ALL SECTIONS: 1. Copying permissions 2. On-line sites that distribute this document 3. "C++-FAQs-Book" versus "On-Line-C++-FAQs" 4. List of recent changes to this document 5. How to post to comp.lang.c++ (Read Before Posting!) 6. Managerial issues 7. Classes and objects 8. References 9. Inline functions 10. Constructors and destructors 11. Operator overloading 12. Friends 13. Input/output via and 14. Freestore management 15. Exceptions and error handling 16. Const correctness 17. Basics of inheritance 18. Inheritance and virtual functions 19. Inheritance and conformance 20. Inheritance and access rules 21. Inheritance and constructors/destructors 22. Private and protected inheritance 23. Abstraction 24. Style guidelines 25. Keys for Smalltalk programmers to learn C++ 26. Reference and value semantics 27. How to mix C and C++ 28. Pointers to member functions 29. Container classes and templates 30. Class libraries 31. Compiler dependencies 32. Miscellaneous technical issues 33. Miscellaneous environmental issues ============================================================================== SECTION [22]: Private and protected inheritance [22.1] How do you express "private inheritance"? When you use : private instead of : public. E.g., class Foo : private Bar { public: // ... }; ============================================================================== [22.2] How are "private inheritance" and "composition" similar? private inheritance is a syntactic variant of composition (has-a). E.g., the "Car has-a Engine" relationship can be expressed using composition: class Engine { public: Engine(int numCylinders); void start(); // Starts this Engine }; class Car { public: Car() : e_(8) { } // Initializes this Car with 8 cylinders void start() { e_.start(); } // Start this Car by starting its Engine private: Engine e_; // Car has-a Engine }; The same "has-a" relationship can also be expressed using private inheritance: class Car : private Engine { // Car has-a Engine public: Car() : Engine(8) { } // Initializes this Car with 8 cylinders Engine::start; // Start this Car by starting its Engine }; There are several similarities between these two forms of composition: * In both cases there is exactly one Engine member object contained in a Car * In neither case can users (outsiders) convert a Car* to an Engine* There are also several distinctions: * The first form is needed if you want to contain several Engines per Car * The second form can introduce unnecessary multiple inheritance * The second form allows members of Car to convert a Car* to an Engine* * The second form allows access to the protected members of the base class * The second form allows Car to override Engine's virtual functions Note that private inheritance is usually used to gain access into the protected: members of the base class, but this is usually a short-term solution (translation: a band-aid; see below). ============================================================================== [22.3] Which should I prefer: composition or private inheritance? Use composition when you can, private inheritance when you have to. Normally you don't want to have access to the internals of too many other classes, and private inheritance gives you some of this extra power (and responsibility). But private inheritance isn't evil; it's just more expensive to maintain, since it increases the probability that someone will change something that will break your code. A legitimate, long-term use for private inheritance is when you want to build a class Fred that uses code in a class Wilma, and the code from class Wilma needs to invoke member functions from your new class, Fred. In this case, Fred calls non-virtuals in Wilma, and Wilma calls (usually pure) virtuals in itself, which are overridden by Fred. This would be much harder to do with composition. class Wilma { protected: void fredCallsWilma() { cout << "Wilma::fredCallsWilma()\n"; wilmaCallsFred(); } virtual void wilmaCallsFred() = 0; }; class Fred : private Wilma { public: void barney() { cout << "Fred::barney()\n"; Wilma::fredCallsWilma(); } protected: virtual void wilmaCallsFred() { cout << "Fred::wilmaCallsFred()\n"; } }; ============================================================================== [22.4] Should I pointer-cast from a private derived class to its base class? Generally, No. From a member function or friend of a privately derived class, the relationship to the base class is known, and the upward conversion from PrivatelyDer* to Base* (or PrivatelyDer& to Base&) is safe; no cast is needed or recommended. However users of PrivateDer should avoid this unsafe conversion, since it is based on a private decision of PrivateDer, and is subject to change without notice. ============================================================================== [22.5] How is protected inheritance related to private inheritance? Similarities: both allow overriding virtuals in the private/protected base class, neither claims the derived is a kind-of its base. Dissimilarities: protected inheritance allows derived classes of derived classes to know about the inheritance relationship. Thus your grand kids are effectively exposed to your implementation details. This has both benefits (it allows subclasses of the protected derived class to exploit the relationship to the protected base class) and costs (the protected derived class can't change the relationship without potentially breaking further derived classes). Protected inheritance uses the : protected syntax: class Car : protected Engine { public: // ... }; ============================================================================== [22.6] What are the access rules with private and protected inheritance? Take these classes as examples: class B { /*...*/ }; class D_priv : private B { /*...*/ }; class D_prot : protected B { /*...*/ }; class D_publ : public B { /*...*/ }; class UserClass { B b; /*...*/ }; None of the subclasses can access anything that is private in B. In D_priv, the public and protected parts of B are private. In D_prot, the public and protected parts of B are protected. In D_publ, the public parts of B are public and the protected parts of B are protected (D_publ is-a-kind-of-a B). class UserClass can access only the public parts of B, which "seals off" UserClass from B. To make a public member of B so it is public in D_priv or D_prot, state the name of the member with a B:: prefix. E.g., to make member B::f(int,float) public in D_prot, you would say: class D_prot : protected B { public: B::f; // Note: Not B::f(int,float) }; ============================================================================== SECTION [23]: Abstraction [23.1] What's the big deal of separating interface from implementation? Interfaces are a company's most valuable resources. Designing an interface takes longer than whipping together a concrete class which fulfills that interface. Furthermore interfaces require the time of more expensive people. Since interfaces are so valuable, they should be protected from being tarnished by data structures and other implementation artifacts. Thus you should separate interface from implementation. ============================================================================== [23.2] How do I separate interface from implementation in C++ (like Modula-2)? Use an ABC (see next FAQ). ============================================================================== [23.3] What is an ABC? An abstract base class. At the design level, an abstract base class (ABC) corresponds to an abstract concept. If you asked a mechanic if he repaired vehicles, he'd probably wonder what kind-of vehicle you had in mind. Chances are he doesn't repair space shuttles, ocean liners, bicycles, or nuclear submarines. The problem is that the term "vehicle" is an abstract concept (e.g., you can't build a "vehicle" unless you know what kind of vehicle to build). In C++, class Vehicle would be an ABC, with Bicycle, SpaceShuttle, etc, being subclasses (an OceanLiner is-a-kind-of-a Vehicle). In real-world OO, ABCs show up all over the place. As programming language level, an ABC is a class that has one or more pure virtual member functions (see next FAQ). You cannot make an object (instance) of an ABC. ============================================================================== [23.4] What is a "pure virtual" member function? A member function declaration that turns a normal class into an abstract class (i.e., an ABC). You normally only implement it a derived class. Some member functions exist in concept; they don't have any reasonable definition. E.g., suppose I asked you to draw a Shape at location (x,y) that has size 7. You'd ask me "what kind of shape should I draw?" (circles, squares, hexagons, etc, are drawn differently). In C++, we must indicate the existence of the draw() member function (so users can call it when they have a Shape* or a Shape&), but we recognize it can (logically) be defined only in subclasses: class Shape { public: virtual void draw() const = 0; // = 0 means it is "pure virtual" // ... }; This pure virtual function makes Shape an ABC. If you want, you can think of the "= 0;" syntax as if the code were at the NULL pointer. Thus Shape promises a service to its users, yet Shape isn't able to provide any code to fulfill that promise. This ensures any actual object created from a [concrete] class derived from Shape will have the indicated member function, even though the base class doesn't have enough information to actually define it yet. Note that it is possible to provide a definition for a pure virtual function, but this usually confuses novices and is best avoided until later. ============================================================================== [23.5] How can I provide printing for an entire hierarchy of classes? Provide a friend operator<< that calls a protected virtual function: class Base { public: friend ostream& operator<< (ostream& o, const Base& b); // ... protected: virtual void print(ostream& o) const; // Or "= 0;" if Base is an ABC }; inline ostream& operator<< (ostream& o, const Base& b) { b.print(o); return o; } class Derived : public Base { protected: virtual void print(ostream& o) const; }; Now all subclasses of Base merely provide their own print(ostream&) const member function (they all share the common operator<<). This technique allows friends to act as if they supported dynamic binding. ============================================================================== [23.6] When should my destructor be virtual? When you may delete a derived object via a base pointer. virtual functions bind to the code associated with the class of the object, rather than with the class of the pointer/reference. When you say delete basePtr, and the base class has a virtual destructor, the destructor that gets invoked is the one associated with the type of the object *basePtr, rather than the one associated with the type of the pointer. This is generally A Good Thing. To make life easy for you, the only time you wouldn't want to make a class's destructor virtual is if that class has no virtual functions, since the introduction of the first virtual function usually imposes some space overhead in each object to implement the magic of dynamic binding. It usually boils down to an extra pointer per object called the "virtual table pointer" or vptr. ============================================================================== [23.7] What is a "virtual constructor"? An idiom that allows you to do something that C++ doesn't directly support. You can get the effect of a virtual constructor by a virtual clone() member function (for copy constructing), or a virtual create() member function (for the default constructor). class Shape { public: virtual ~Shape() { } // See on "virtual destructors" for more virtual void draw() = 0; virtual void move() = 0; // ... virtual Shape* clone() const = 0; // Uses the copy ctor virtual Shape* create() const = 0; // Uses the default ctor }; class Circle : public Shape { public: Circle* clone() const { return new Circle(*this); } Circle* create() const { return new Circle(); } // ... }; In the clone() member function, the new Circle(*this) code calls Circle's copy constructor to copy the state of this into the newly created Circle object. In the create() member function, the new Circle() code calls Circle's default constructor. Users use these as if they were "virtual constructors": void userCode(Shape& s) { Shape* s2 = s.clone(); Shape* s3 = s.create(); // ... delete s2; // Relies on destructor being virtual ! delete s3; // Ditto } This function will work correctly regardless of whether the Shape is a Circle, Square, or some other kind-of Shape that doesn't even exist yet. ============================================================================== SECTION [24]: Style guidelines [24.1] What are some good C++ coding standards? Thank you for reading this answer rather than just trying to set your own coding standards. But beware that some people on comp.lang.c++ are very sensitive on this issue. Nearly every software engineer has, at some point, been exploited by someone who used coding standards as a "power play." Furthermore some attempts to set C++ coding standards have been made by those who didn't know what they were talking about, so the standards end up being based on what was the state-of-the-art when the standards setters where writing code. Such impositions generate an attitude of mistrust for coding standards. Obviously anyone who asks this question wants to be trained so they don't run off on their own ignorance, but nonetheless posting a question such as this one to comp.lang.c++ tends to generate more heat than light. ============================================================================== [24.2] Are coding standards necessary? Are they sufficient? Coding standards do not make non-OO programmers into OO programmers; only training and experience do that. If coding standards have merit, it is that they discourage the petty fragmentation that occurs when large organizations coordinate the activities of diverse groups of programmers. But you really want more than a coding standard. The structure provided by coding standards gives neophytes one less degree of freedom to worry about, which is good. However pragmatic guidelines should go well beyond pretty-printing standards. Organizations need a consistent philosophy of design and implementation. E.g., strong or weak typing? references or pointers in interfaces? stream I/O or stdio? should C++ code call C code? vice versa? how should ABCs be used? should inheritance be used as an implementation technique or as a specification technique? what testing strategy should be employed? inspection strategy? should interfaces uniformly have a get() and/or set() member function for each data member? should interfaces be designed from the outside-in or the inside-out? should errors be handled by try/catch/throw or by return codes? etc. What is needed is a "pseudo standard" for detailed design. I recommend a three-pronged approach to achieving this standardization: training, mentoring, and libraries. Training provides "intense instruction," mentoring allows OO to be caught rather than just taught, and high quality C++ class libraries provide "long term instruction." There is a thriving commercial market for all three kinds of "training." Advice by organizations who have been through the mill is consistent: Buy, Don't Build. Buy libraries, buy training, buy tools, buy consulting. Companies who have attempted to become a self-taught tool-shop as well as an application/system shop have found success difficult. Few argue that coding standards are "ideal," or even "good," however they are necessary in the kind of organizations/situations described above. The following FAQs provide some basic guidance in conventions and styles. ============================================================================== [24.3] Should our organization determine coding standards from our C experience? No! No matter how vast your C experience, no matter how advanced your C expertise, being a good C programmer does not make you a good C++ programmer. Converting from C to C++ is more than just learning the syntax and semantics of the ++ part of C++. Organizations who want the promise of OO, but who fail to put the "OO" into "OO programming", are fooling themselves; the balance sheet will show their folly. C++ coding standards should be tempered by C++ experts. Asking comp.lang.c++ is a start. Seek out experts who can help guide you away from pitfalls. Get training. Buy libraries and see if "good" libraries pass your coding standards. Do not set standards by yourself unless you have considerable experience in C++. Having no standard is better than having a bad standard, since improper "official" positions "harden" bad brain traces. There is a thriving market for both C++ training and libraries from which to pool expertise. One more thing: whenever something is in demand, the potential for charlatans increases. Look before you leap. Also ask for student-reviews from past companies, since not even expertise makes someone a good communicator. Finally, select a practitioner who can teach, not a full time teacher who has a passing knowledge of the language/paradigm. ============================================================================== [24.4] Should I declare locals in the middle of a function or at the top? Declare near first use. An object is initialized (constructed) the moment it is declared. If you don't have enough information to initialize an object until half way down the function, you should create it half way down the function when it can be initialized correctly. Don't initialize it to an "empty" value at the top then "assign" it later. The reason for this is runtime performance. Building an object correctly is faster than building it incorrectly and remodeling it later. Simple examples show a factor of 350% speed hit for simple classes like String. Your mileage may vary; surely the overall system degradation will be less that 350%, but there will be degradation. Unnecessary degradation. A common retort to the above is: "we'll provide set() member functions for every datum in our objects so the cost of construction will be spread out." This is worse than the performance overhead, since now you're introducing a maintenance nightmare. Providing a set() member function for every datum is tantamount to public data: you've exposed your implementation technique to the world. The only thing you've hidden is the physical names of your member objects, but the fact that you're using a List and a String and a float, for example, is open for all to see. Bottom line: Locals should be declared near their first use. Sorry that this isn't familiar to C experts, but new doesn't necessarily mean bad. ============================================================================== [24.5] What source-file-name convention is best? foo.cpp? foo.C? foo.cc? If you already have a convention, use it. If not, consult your compiler to see what the compiler expects. Typical answers are: .C, .cc, .cpp, or .cxx (naturally the .C extension assumes a case-sensitive file system to distinguish .C from .c). At Paradigm Shift, Inc., we have used both .cpp for our C++ source files, and we have also used .C. In the latter case, we supply the compiler option forces .c files to be treated as C++ source files (-Tdp for IBM CSet++, -cpp for Zortech C++, -P for Borland C++, etc.) when porting to case-insensitive file systems. None of these approaches have any striking technical superiority to the others; we generally use whichever technique is preferred by our customer (again, these issues are dominated by business considerations, not by technical considerations). ============================================================================== [24.6] What header-file-name convention is best? foo.H? foo.hh? foo.hpp? If you already have a convention, use it. If not, and if you don't need your editor to distinguish between C and C++ files, simply use .h. Otherwise use whatever the editor wants, such as .H, .hh, or .hpp. At Paradigm Shift, Inc., we tend to use either .hpp or .h for our C++ header files. ============================================================================== [24.7] Are there any lint-like guidelines for C++? Yes, there are some practices which are generally considered dangerous. However none of these are universally "bad," since situations arise when even the worst of these is needed: * A class Fred's assignment operator should return *this as a Fred& (allows chaining of assignments) * A class with any virtual functions ought to have a virtual destructor * A class with any of {destructor, assignment operator, copy constructor} generally needs all 3 * A class Fred's copy constructor and assignment operator should have const in the parameter: respectively Fred::Fred(const Fred&) and Fred& Fred::operator= (const Fred&) * When initializing an object's member objects in the constructor, always use initialization lists rather than assignment. The performance difference for user-defined classes can be substantial (3x!) * Many assignment operators should start by testing to avoid assignment-to-self. E.g., Fred& Fred::operator= (const Fred& fred) { if (this == &fred) return *this; // ...Normal assignment duties... return *this; } Sometimes there is no need to check, but these situations generally correspond to when there's no need for an explicit user-specified assignment operator (as opposed to a compiler-synthesized assignment operator). * In classes that define both +=, + and =, a += b and a = a + b should generally do the same thing; ditto for the other identities of built-in types (e.g., a += 1 and ++a; p[i] and *(p+i); etc). This can be enforced by writing the binary operations using the "op=" forms. E.g., Fred operator+ (const Fred& a, const Fred& b) { Fred ans = a; ans += b; return ans; } This way the "constructive" binary operators don't even need to be friends. But it is sometimes possible to more efficiently implement common operations (e.g., if class Fred is actually String, and += has to reallocate/copy string memory, it may be better to know the eventual length from the beginning). ============================================================================== SECTION [25]: Keys for Smalltalk programmers to learn C++ [25.1] Why does C++'s FAQ have a section on Smalltalk? Is this Smalltalk-bashing? The two "major" OO programming languages in the world are C++ and Smalltalk. Due to its popularity as the OO programming language with the second largest user pool, many new C++ programmers come from a Smalltalk background. This section answers the questions: * What's different about the two languages * What must a Smalltalk-turned-C++ programmer know to master C++ This section does not attempt to answer the questions: * Which language is "better"? * Why is Smalltalk "bad"? * Why is C++ "bad"? Nor is it an open invitation for some Smalltalk terrorist to slash my tires while I sleep (on those rare occasions when I have time to rest these days :-). ============================================================================== [25.2] What's the difference between C++ and Smalltalk? The most important differences are: * Static typing vs dynamic typing * Whether inheritance must be used only for subtyping * Value vs reference semantics The first two differences are illuminated in the remainder of this section. The third point is the subject of the section that follows. If you're a Smalltalk programmer who wants to learn C++, you'd be very wise to study the next three FAQs carefully. ============================================================================== [25.3] What is "static typing," and how is it similar/dissimilar to Smalltalk? Static typing says the compiler checks the type safety of every operation statically (at compile-time), rather than to generate code which will check things at run-time. For example, with static typing, the signature matching for function arguments is checked at compile time, not at run-time. An improper match is flagged as an error by the compiler, not by the run-time system. In OO code, the most common "typing mismatch" is invoking a member function against an object which isn't prepared to handle the operation. E.g., if class Fred has member function f() but not g(), and fred is an instance of class Fred, then fred.f() is legal and fred.g() is illegal. C++ (statically typed) catches the error at compile time, and Smalltalk (dynamically typed) catches the error at run-time. (Technically speaking, C++ is like Pascal --pseudo statically typed-- since pointer casts and unions can be used to violate the typing system; which reminds me: only use pointer casts and unions as often as you use gotos). ============================================================================== [25.4] Which is a better fit for C++: "static typing" or "dynamic typing"? If you want to use C++ most effectively, use it as a statically typed language. C++ is flexible enough that you can (via pointer casts, unions, and #define macros) make it "look" like Smalltalk. But don't. Which reminds me: try to avoid #define. There are places where pointer casts and unions are necessary and even wholesome, but they should be used carefully and sparingly. A pointer cast tells the compiler to believe you. An incorrect pointer cast might corrupt your heap, scribble into memory owned by other objects, call nonexistent member functions, and cause general failures. It's not a pretty sight. If you avoid these and related constructs, you can make your C++ code both safer and faster, since anything that can be checked at compile time is something that doesn't have to be done at run-time. If you're interested in using a pointer cast, use the new style pointer casts. The most common example of these is to change old-style pointer casts such as (X*)p into new-style dynamic casts such as dynamic_cast(p), where p is a pointer and X is a type. In addition to dynamic_cast, there is static_cast and const_cast, but dynamic_cast is the one that simulates most of the advantages of dynamic typing (the other is the typeid() construct; for example, typeid(*p).name() will return the name of the type of *p). ============================================================================== [25.5] How can you tell if you have a dynamically typed C++ class library? * Hint #1: when everything is derived from a single root class, usually Object. * Hint #2: when the container classes (List, Stack, Set, etc) are non-templates. * Hint #3: when the container classes (List, Stack, Set, etc) insert/extract elements as pointers to Object. This lets you put an Apple into such a container, but when you get it out, the compiler knows only that it is derived from Object, so you have to use a pointer cast to convert it back to an Apple*; and you better pray a lot that it really is an Apple, cause your blood is on your own head). You can make the pointer cast "safe" by using dynamic_cast, but this dynamic testing is just that: dynamic. This coding style is the essence of dynamic typing in C++. You call a function that says "convert this Object into an Apple or give me NULL if its not an Apple," and you've got dynamic typing: you don't know what will happen until run-time. When you use "templates" to implement your containers, the C++ compiler can statically validate 90+% of an application's typing information (the figure "90+%" is apocryphal; some claim they always get 100%, those who need persistence get something less than 100% static type checking). The point is: C++ gets genericity from templates, not from inheritance. ============================================================================== [25.6] How do you use inheritance in C++, and is that different from Smalltalk? Some people believe that the purpose of inheritance is code reuse. In C++, this is wrong. Stated plainly, "inheritance is not for code reuse." The purpose of inheritance in C++ is to express interface compliance (subtyping), not to get code reuse. In C++, code reuse usually comes via composition rather than via inheritance. In other words, inheritance is mainly a specification technique rather than an implementation technique. This is a major difference with Smalltalk, where there is only one form of inheritance (C++ provides private inheritance to mean "share the code but don't conform to the interface", and public inheritance to mean "kind-of"). The Smalltalk language proper (as opposed to coding practice) allows you to have the effect of "hiding" an inherited method by providing an override that calls the "does not understand" method. Furthermore Smalltalk allows a conceptual "is-a" relationship to exist apart from the subclassing hierarchy (subtypes don't have to be subclasses; e.g., you can make something that is-a Stack yet doesn't inherit from class Stack). In contrast, C++ is more restrictive about inheritance: there's no way to make a "conceptual is-a" relationship without using inheritance (the C++ work-around is to separate interface from implementation via ABCs). The C++ compiler exploits the added semantic information associated with public inheritance to provide static typing. ============================================================================== [25.7] What are the practical consequences of differences in Smalltalk/C++ inheritance? Smalltalk lets you make a subtype that isn't a subclass, and allows you to make a subclass that isn't a subtype. This allows Smalltalk programmers to be very carefree in putting data (bits, representation, data structure) into a class (e.g., you might put a linked list into class Stack). After all, if someone wants an array-based-Stack, they don't have to inherit from Stack; they could inherit such a class from Array if desired, even though an ArrayBasedStack is not a kind-of Array! In C++, you can't be nearly as carefree. Only mechanism (member function code), but not representation (data bits) can be overridden in subclasses. Therefore you're usually better off not putting the data structure in a class. This leads to a stronger reliance on abstract base classes (ABCs). I like to think of the difference between an ATV and a Maseratti. An ATV (all terrain vehicle) is more fun, since you can "play around" by driving through fields, streams, sidewalks, and the like. A Maseratti, on the other hand, gets you there faster, but it forces you to stay on the road. My advice to C++ programmers is simple: stay on the road. Even if you're one of those people who like the "expressive freedom" to drive through the bushes, don't do it in C++; it's not a good fit. ============================================================================== [25.8] Do you need to learn a "pure" OO programming language before you learn C++? No (in fact, doing so might actually hurt you). (Note that Smalltalk is a "pure" OO programming language and C++ is a "hybrid" OO programming language). Before reading this, please read the previous FAQs on the difference between C++ and Smalltalk. The "purity" of the OO programming language doesn't make the transition to C++ any easier. In fact, the typical use of dynamic typing and non-subtyping inheritance can make it even harder for Smalltalk programmers to learn C++. Paradigm Shift, Inc., has taught OO technology to literally thousands of people, and we have noticed that people who want to learn C++ from a Smalltalk background usually have just as hard a time as those who've never seen inheritance before. In fact, those with extensive experience with a dynamically typed OO programming language (usually but not always Smalltalk) might even have a harder time, since it's harder to unlearn habits than it is to learn the statically typed way from the beginning. ============================================================================== [25.9] What is the NIHCL? Where can I get it? NIHCL stands for "National-Institute-of-Health's-class-library." It can be acquired via ftp://128.231.128.7/pub/NIHCL/nihcl-3.0.tar.Z NIHCL (some people pronounce it "N-I-H-C-L," others pronounce it like "nickel") is a C++ translation of the Smalltalk class library. There are some ways where NIHCL's use of dynamic typing helps (e.g., persistent objects). There are also places where its use of dynamic typing creates tension with the static typing of the C++ language. See previous FAQs on Smalltalk for more. ============================================================================== SECTION [26]: Reference and value semantics [26.1] What is value and/or reference semantics, and which is best in C++? With reference semantics, assignment is a pointer-copy (i.e., a reference). Value (or "copy") semantics mean assignment copies the value, not just the pointer. C++ gives you the choice: use the assignment operator to copy the value (copy/value semantics), or use a pointer-copy to copy a pointer (reference semantics). C++ allows you to override the assignment operator to do anything your heart desires, however the default (and most common) choice is to copy the value. Pros of reference semantics: flexibility and dynamic binding (you get dynamic binding in C++ only when you pass by pointer or pass by reference, not when you pass by value). Pros of value semantics: speed. "Speed" seems like an odd benefit to for a feature that requires an object (vs a pointer) to be copied, but the fact of the matter is that one usually accesses an object more than one copies the object, so the cost of the occasional copies is (usually) more than offset by the benefit of having an actual object rather than a pointer to an object. There are three cases when you have an actual object as opposed to a pointer to an object: local objects, global/static objects, and fully contained member objects in a class. The most important of these is the last ("composition"). More info about copy-vs-reference semantics is given in the next FAQs. Please read them all to get a balanced perspective. The first few have intentionally been slanted toward value semantics, so if you only read the first few of the following FAQs, you'll get a warped perspective. Assignment has other issues (e.g., shallow vs deep copy) which are not covered here. ============================================================================== [26.2] What is "virtual data," and how-can / why-would I use it in C++? virtual data allows a derived class to change the exact class of a base class's member object. virtual data isn't strictly "supported" by C++, however it can be simulated in C++. It ain't pretty, but it works. To simulate virtual data in C++, the base class must have a pointer to the member object, and the derived class must provide a new object to be pointed to by the base class's pointer. The base class would also have one or more normal constructors that provide their own referent (again via new), and the base class's destructor would delete the referent. For example, class Stack might have an Array member object (using a pointer), and derived class StretchableStack might override the base class member data from Array to StretchableArray. For this to work, StretchableArray would have to inherit from Array, so Stack would have an Array*. Stack's normal constructors would initialize this Array* with a new Array, but Stack would also have a (possibly protected:) constructor that would accept an Array* from a derived class. StretchableArray's constructor would provide a new StretchableArray to this special constructor. Pros: * Easier implementation of StretchableStack (most of the code is inherited) * Users can pass a StretchableStack as a kind-of Stack Cons: * Adds an extra layer of indirection to access the Array * Adds some extra freestore allocation overhead (both new and delete) * Adds some extra dynamic binding overhead (reason given in next FAQ) In other words, we succeeded at making our job easier as the implementer of StretchableStack, but all our users pay for it. Unfortunately the extra overhead was imposed on both users of StretchableStack and on users of Stack. See the FAQ after the next to find out how much the users "pay." Also: please read the few FAQs that follow the next one too (you will not get a balanced perspective without the others). ============================================================================== [26.3] What's the difference between virtual data and dynamic data? The easiest way to see the distinction is by an analogy with "virtual functions": A virtual member function means the declaration (signature) must stay the same in subclasses, but the definition (body) can be overridden. The overriddenness of an inherited member function is a static property of the subclass; it doesn't change dynamically throughout the life of any particular object, nor is it possible for distinct objects of the subclass to have distinct definitions of the member function. Now go back and re-read the previous paragraph, but make these substitutions: * "member function" --> "member object" * "signature" --> "type" * "body" --> "exact class" After this, you'll have a working definition of virtual data. Another way to look at this is to distinguish "per-object" member functions from "dynamic" member functions. A "per-object" member function is a member function that is potentially different in any given instance of an object, and could be implemented by burying a function pointer in the object; this pointer could be const, since the pointer will never be changed throughout the object's life. A "dynamic" member function is a member function that will change dynamically over time; this could also be implemented by a function pointer, but the function pointer would not be const. Extending the analogy, this gives us three distinct concepts for data members: * virtual data: the definition (class) of the member object is overridable in subclasses provided its declaration ("type") remains the same, and this overriddenness is a static property of the subclass * per-object-data: any given object of a class can instantiate a different conformal (same type) member object upon initialization (usually a "wrapper" object), and the exact class of the member object is a static property of the object that wraps it * dynamic-data: the member object's exact class can change dynamically over time The reason they all look so much the same is that none of this is "supported" in C++. It's all merely "allowed," and in this case, the mechanism for faking each of these is the same: a pointer to a (probably abstract) base class. In a language that made these "first class" abstraction mechanisms, the difference would be more striking, since they'd each have a different syntactic variant. ============================================================================== [26.4] Should I normally use pointers to freestore allocated objects for my data members, or should I use "composition"? Composition. Your member objects should normally be "contained" in the composite object (but not always; "wrapper" objects are a good example of where you want a pointer/reference; also the N-to-1-uses-a relationship needs something like a pointer/reference). There are three reasons why fully contained member objects ("composition") has better performance than pointers to freestore-allocated member objects: * Extra layer to indirection every time you need to access the member object * Extra freestore allocations (new in constructor, delete in destructor) * Extra dynamic binding (reason given below) ============================================================================== [26.5] What are relative costs of the 3 performance hits associated with allocating member objects from the freestore? The three performance hits are enumerated in the previous FAQ: * By itself, an extra layer of indirection is small potatoes * Freestore allocations can be a performance issue (the performance of the typical implementation of malloc degrades when there are many allocations; OO s/w can easily become "freestore bound" unless you're careful) * The extra dynamic binding comes from having a pointer rather than an object. Whenever the C++ compiler can know an object's exact class, virtual function calls can be statically bound, which allows inlining. Inlining allows zillions (would you believe half a dozen :-) optimization opportunities such as procedural integration, register lifetime issues, etc. The C++ compiler can know an object's exact class in three circumstances: local variables, global/static variables, and fully-contained member objects Thus fully-contained member objects allow significant optimizations that wouldn't be possible under the "member objects-by-pointer" approach. This is the main reason that languages which enforce reference-semantics have "inherent" performance challenges. Note: Please read the next three FAQs to get a balanced perspective! ============================================================================== [26.6] Are "inline virtual" member functions ever actually "inlined"? Occasionally... A virtual call via a pointer or reference is always resolved dynamically, which can never be inlined. Reason: the compiler can't know which actual code to call until run-time (i.e., dynamically), since the code may be from a derived class that was created after the caller was compiled. Therefore the only time an inline virtual call can be inlined is when the compiler knows the "exact class" of the object which is the target of the virtual function call. This can happen only when the compiler has an actual object rather than a pointer or reference to an object. I.e., either with a local object, a global/static object, or a fully contained object inside a composite. Note that the difference between inlining and non-inlining is normally much more significant than the difference between a regular function call and a virtual function call. For example, the difference between a regular function call and a virtual function call is often just two extra memory references, but the difference between an inline function and a non-inline function can be as much as an order of magnitude (for zillions of calls to insignificant member functions, loss of inlining virtual functions can result in 25X speed degradation! [Doug Lea, "Customization in C++," proc Usenix C++ 1990]). A practical consequence of this insight: don't get bogged down in the endless debates (or sales tactics!) of compiler/language vendors who compare the cost of a virtual function call on their language/compiler with the same on another language/compiler. Such comparisons are largely meaningless when compared with the ability of the language/compiler to "inline expand" member function calls. I.e., many language implementation vendors make a big stink about how good their dispatch strategy is, but if these implementations don't inline member function calls, the overall system performance would be poor, since it is inlining --not dispatching-- that has the greatest performance impact. Note: Please read the next two FAQs to see the other side of this coin! ============================================================================== [26.7] Sounds like I should never use reference semantics, right? Wrong. Reference semantics are A Good Thing. We can't live without pointers. We just don't want our s/w to be One Gigantic Rats Nest Of Pointers. In C++, you can pick and choose where you want reference semantics (pointers/references) and where you'd like value semantics (where objects physically contain other objects etc). In a large system, there should be a balance. However if you implement absolutely everything as a pointer, you'll get enormous speed hits. Objects near the problem skin are larger than higher level objects. The identity of these "problem space" abstractions is usually more important than their "value." Thus reference semantics should be used for problem-space objects. Note that these problem space objects are normally at a higher level of abstraction than the solution space objects, so the problem space objects normally have a relatively lower frequency of interaction. Therefore C++ gives us an ideal situation: we choose reference semantics for objects that need unique identity or that are too large to copy, and we can choose value semantics for the others. Thus the highest frequency objects will end up with value semantics, since we install flexibility where it doesn't hurt us (only), and we install performance where we need it most! These are some of the many issues the come into play with real OO design. OO/C++ mastery takes time and high quality training. If you want a powerful tool, you've got to invest. Don't stop now! Read the next FAQ too!! ============================================================================== [26.8] Does the poor performance of reference semantics mean I should pass-by-value? Nope. The previous FAQ were talking about member objects, not parameters. Generally, objects that are part of an inheritance hierarchy should be passed by reference or by pointer, not by value, since only then do you get the (desired) dynamic binding (pass-by-value doesn't mix with inheritance, since larger subclass objects get "sliced" when passed by value as a base class object). Unless compelling reasons are given to the contrary, member objects should be by value and parameters should be by reference. The discussion in the previous few FAQs indicates some of the "compelling reasons" for when member objects should be by reference. ============================================================================== Path: senator-bedfellow.mit.edu!bloom-beacon.mit.edu!paperboy.osf.org!bone.think.com!blanket.mitre.org!news.mathworks.com!newsfeed.internetmci.com!panix!news.columbia.edu!news.new-york.net!wlbr!news.cerf.net!nic.cerf.net!mpcline From: mpcline@nic.cerf.net (Marshall Cline) Newsgroups: comp.lang.c++ Subject: C++ FAQ: posting #4/4 [IGNORE EARLIER POSTING!] Followup-To: comp.lang.c++ Date: 26 Apr 1996 21:22:45 GMT Organization: Paradigm Shift, Inc (technology consulting) Lines: 996 Sender: cline@parashift.com Distribution: world Expires: +1 month Message-ID: <4lrer5$33r@news.cerf.net> Reply-To: cline@parashift.com (Marshall Cline) NNTP-Posting-Host: nic.cerf.net Summary: Please read this before posting to comp.lang.c++ Archive-name: C++-faq/part4_4 [PLEASE NOTE: PLEASE IGNORE THE EARLIER POSTING OF THE FAQ (it had an error in the URL for the HTML version of the FAQ)]. BIG NEWS: * The content of this document has been extensively updated. * An HTML version that is broken up by sections is now available at: http://www.cerfnet.com/~mpcline/On-Line-C++-FAQs/ Posting 4 of 4. The On-Line C++ FAQs (Frequently Asked Questions) Revised Apr 26, 1996 ============================================================================== COMMON PREFIX INFORMATION: AUTHOR: Marshall P. Cline, Ph.D., cline@parashift.com Paradigm Shift, Inc. / One Park St. / Norwood, NY 13668 315-353-6100 (voice) / 315-353-6110 (fax) COPYRIGHT: This document (the "On-Line C++ FAQs") is Copyright (C) 1991-96 Marshall P. Cline, Ph.D., cline@parashift.com. All rights reserved. Copying is permmitted only under designated situations (see section [1] for permissions). NO WARRANTY: THIS WORK IS PROVIDED ON AN "AS IS" BASIS. THE AUTHOR PROVIDES NO WARRANTY WHATSOEVER, EITHER EXPRESS OR IMPLIED, REGARDING THE WORK, INCLUDING WARRANTIES WITH RESPECT TO ITS MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. On-Line-C++-FAQs != C++-FAQs-Book: Note: This document (the "On-Line C++ FAQs") is not the same as the "C++ FAQs" book (e.g., the "C++ FAQs" book is five times larger than this on-line document). The "C++ FAQs" book is available in bookstores ("C++ FAQs" by Cline and Lomow, Addison-Wesley, 1995, ISBN 0-201-58958-3; see also http://heg-school.aw.com/cseng/authors/cline/FAQ/FAQ.html). ============================================================================== OVERVIEW OF ALL SECTIONS: 1. Copying permissions 2. On-line sites that distribute this document 3. "C++-FAQs-Book" versus "On-Line-C++-FAQs" 4. List of recent changes to this document 5. How to post to comp.lang.c++ (Read Before Posting!) 6. Managerial issues 7. Classes and objects 8. References 9. Inline functions 10. Constructors and destructors 11. Operator overloading 12. Friends 13. Input/output via and 14. Freestore management 15. Exceptions and error handling 16. Const correctness 17. Basics of inheritance 18. Inheritance and virtual functions 19. Inheritance and conformance 20. Inheritance and access rules 21. Inheritance and constructors/destructors 22. Private and protected inheritance 23. Abstraction 24. Style guidelines 25. Keys for Smalltalk programmers to learn C++ 26. Reference and value semantics 27. How to mix C and C++ 28. Pointers to member functions 29. Container classes and templates 30. Class libraries 31. Compiler dependencies 32. Miscellaneous technical issues 33. Miscellaneous environmental issues ============================================================================== SECTION [27]: How to mix C and C++ [27.1] How can I call a C function f(int,char,float) from C++ code? Tell the C++ compiler that it is a C function: extern "C" void f(int,char,float); Be sure to include the full function prototype. A block of many C functions can be grouped via braces, as in: extern "C" { void f(int, char, float); int g(char* s, const char* s2); double sqrtOfSumOfSquares(double a, double b); } ============================================================================== [27.2] How can I include a C header file in my C++ code? If it's a standard header file, you don't have to do anything unusual. E.g., #include If it's not one of the system-provided standard header files, you may need to wrap the #include line in an extern "C" { /*...*/ } construct (but please note that this is not necessary for the standard header files such as ): extern "C" { #include "my-C-code.h" } Note: If you have the ability to change the .h file, please see the next FAQ. ============================================================================== [27.3] How can I modify a C header file so it can be #included in C++ code? If the C header file is a standard header (e.g., ), you don't have to do anything; see two FAQs back. If you can't change the header file (e.g., if you don't have write access to the file), see the previous FAQ. If you are able to change the C header file, you should strongly consider adding the extern "C" {...} logic inside the header file to make it easier for C++ users to #include it into their C++ code. Naturally you must wrap the extern "C" { and } lines in an #ifdef so they won't be seen by normal C compilers. Step #1: put the following lines at the very top of your C header file: #ifdef __cplusplus extern "C" { #endif Step #2: put the following lines at the very bottom of your C header file: #ifdef __cplusplus } #endif ============================================================================== [27.4] How can I create a C++ function f(int,char,float) that is callable by my C code? The C++ compiler must know that f(int,char,float) is to be called by a C compiler using the same extern "C" construct (see the previous FAQ for details): extern "C" void f(int,char,float); Then you define the function in your C++ module: void f(int x, char y, float z) { // ... } The extern "C" line tells the compiler that the external information sent to the linker should use C calling conventions and name mangling (e.g., preceded by a single underscore). Since name overloading isn't supported by C, you can't make several overloaded functions simultaneously callable by a C program. Caveats and implementation dependencies: * your main() should be compiled with your C++ compiler (for static initialization) * your C++ compiler should direct the linking process (for special libraries) * your C and C++ compilers may need to come from same vendor and have compatible versions (i.e., needs same calling convention, etc) ============================================================================== [27.5] Why is the linker giving errors for C/C++ functions being called from C++/C functions? See the previous two FAQs on how to use extern "C". ============================================================================== [27.6] How can I pass an object of a C++ class to/from a C function? Here's an example: /****** C/C++ header file: Fred.h ******/ #ifdef __cplusplus /* __cplusplus is #defined if/only-if compiler is C++ */ extern "C" { #endif #ifdef __STDC__ extern void c_function(struct Fred*); /* ANSI-C prototypes */ extern struct Fred* cplusplus_callback_function(struct Fred*); #else extern void c_function(); /* K&R style */ extern struct Fred* cplusplus_callback_function(); #endif #ifdef __cplusplus } #endif #ifdef __cplusplus class Fred { public: Fred(); void wilma(int); private: int a_; }; #endif Fred.cpp would be a C++ module: #include "Fred.h" Fred::Fred() : a_(0) { } void Fred::wilma(int a) { } Fred* cplusplus_callback_function(Fred* fred) { fred->wilma(123); return fred; } main.cpp would be a C++ module: #include "Fred.h" int main() { Fred fred; c_function(&fred); return 0; } "c-function.c" would be a C module: #include "Fred.h" void c_function(struct Fred* fred) { cplusplus_callback_function(fred); } Passing pointers to C++ objects to/from C functions will fail if you pass and get back something that isn't exactly the same pointer. For example, don't pass a base class pointer and receive back a derived class pointer, since your C compiler won't understand the pointer conversions necessary to handle multiple and/or virtual inheritance. ============================================================================== [27.7] Can my C function access data in an object of a C++ class? Sometimes. (First read the previous FAQ on passing C++ objects to/from C functions.) You can safely access a C++ object's data from a C function if the C++ class: * has no virtual functions (including inherited virtual functions) * has all its data in the same access-level section (private/protected/public) * has no fully-contained subobjects with virtual functions If the C++ class has any base classes at all (or if any fully contained subobjects have base classes), accessing the data will technically be non-portable, since class layout under inheritance isn't imposed by the language. However in practice, all C++ compilers do it the same way: the base class object appears first (in left-to-right order in the event of multiple inheritance), and subobjects follow. Furthermore, if the class (or any base class) contains any virtual functions, you can often (but less than always) assume a void* appears in the object either at the location of the first virtual function or as the first word in the object. Again, this is not required by the language, but it is the way "everyone" does it. If the class has any virtual base classes, it is even more complicated and less portable. One common implementation technique is for objects to contain an object of the virtual base class (V) last (regardless of where V shows up as a virtual base class in the inheritance hierarchy). The rest of the object's parts appear in the normal order. Every derived class that has V as a virtual base class actually has a pointer to the V part of the final object. ============================================================================== [27.8] Why do I feel like I'm "further from the machine" in C++ as opposed to C? Because you are. As an OO programming language, C++ allows you to model the problem domain itself, which allows you to program in the language of the problem domain rather than in the language of the solution domain. One of C's great strengths is the fact that it has "no hidden mechanism": what you see is what you get. You can read a C program and "see" every clock cycle. This is not the case in C++; old line C programmers (such as many of us once were) are often ambivalent (can anyone say, "hostile") about this feature, but they soon realize that it provides a level of abstraction and economy of expression which lowers maintenance costs without destroying run-time performance. Naturally you can write bad code in any language; C++ doesn't guarantee any particular level of quality, reusability, abstraction, or any other measure of "goodness." C++ doesn't try to make it impossible for bad programmers to write bad programs; it enables reasonable developers to create superior software. ============================================================================== SECTION [28]: Pointers to member functions [28.1] Is the type of "pointer-to-member-function" different from "pointer-to-function"? Yep. Consider the following function: int f(char a, float b); The type of this function is different depending on whether it is an ordinary function or a non-static member function of some class: * It's type is "int (*)(char,float)" if an ordinary function * It's type is "int (Fred::*)(char,float)" if a non-static member function of class Fred Note: if it's a static member function of class Fred, its type is the same as if it was an ordinary function: "int (*)(char,float)". ============================================================================== [28.2] How do I pass a pointer to member function to a signal handler, X event callback, etc? Don't. Because a member function is meaningless without an object to invoke it on, you can't do this directly (if The X Windows System was rewritten in C++, it would probably pass references to objects around, not just pointers to functions; naturally the objects would embody the required function and probably a whole lot more). As a patch for existing software, use a top-level (non-member) function as a wrapper which takes an object obtained through some other technique (held in a global, perhaps). The top-level function would apply the desired member function against the global object. E.g., suppose you want to call Fred::memberFunction() on interrupt: class Fred { public: void memberFunction(); static void staticMemberFunction(); // A static member function can handle it // ... }; // Wrapper function uses a global to remember the object: Fred* object_which_will_handle_signal; void Fred_memberFunction_wrapper() { object_which_will_handle_signal->memberFunction(); } main() { /* signal(SIGINT, Fred::memberFunction); */ // Can NOT do this signal(SIGINT, Fred_memberFunction_wrapper); // OK signal(SIGINT, Fred::staticMemberFunction); // Also OK } Note: static member functions do not require an actual object to be invoked, so pointers-to-static-member-functions are type compatible with regular pointers-to-functions. ============================================================================== [28.3] Why do I keep getting compile errors (type mismatch) when I try to use a member function as an interrupt service routine? This is a special case of the previous two questions, therefore read the previous two answers first. Non-static member functions have a hidden parameter that corresponds to the this pointer. The this pointer points to the instance data for the object. The interrupt hardware/firmware in the system is not capable of providing the this pointer argument. You must use "normal" functions (non class members) or static member functions as interrupt service routines. One possible solution is to use a static member as the interrupt service routine and have that function look somewhere to find the instance/member pair that should be called on interrupt. Thus the effect is that a member function is invoked on an interrupt, but for technical reasons you need to call an intermediate function first. ============================================================================== [28.4] Why am I having trouble taking the address of a C++ function? This is a corollary to the previous FAQ. Long answer: In C++, member functions have an implicit parameter which points to the object (the this pointer inside the member function). Normal C functions can be thought of as having a different calling convention from member functions, so the types of their pointers (pointer-to-member-function vs pointer-to-function) are different and incompatible. C++ introduces a new type of pointer, called a pointer-to-member, which can be invoked only by providing an object. NOTE: do not attempt to "cast" a pointer-to-member-function into a pointer-to-function; the result is undefined and probably disastrous. E.g., a pointer-to-member-function is not required to contain the machine address of the appropriate function. As was said in the last example, if you have a pointer to a regular C function, use either a top-level (non-member) function, or a static (class) member function. ============================================================================== [28.5] How do I declare an array of pointers to member functions? Keep your sanity with typedef. class Fred { public: int f(char x, float y); int g(char x, float y); int h(char x, float y); int i(char x, float y); // ... }; typedef int (Fred::*FredPtr)(char x, float y); Here's the array of pointers to member functions: FredPtr a[4] = { &Fred::f, &Fred::g, &Fred::h, &Fred::i }; To call one of the member functions on object "fred": void userCode(Fred& fred, int memberFunctionNum, char x, float y) { // Assume memberFunctionNum is between 0 and 3 inclusive (fred.*a[memberFunctionNum])(x, y); } You can make the call somewhat clearer using a #define macro: #define callMemberFunction(object,ptrToMember) ((object).*(ptrToMember)) callMemberFunction(fred, a[memberFunctionNum]) (x, y); ============================================================================== SECTION [29]: Container classes and templates [29.1] How can I build a of objects of different types? You can't, but you can fake it pretty well. In C/C++ all arrays are homogeneous (i.e., the elements are all the same type). However, with an extra layer of indirection you can give the appearance of a heterogeneous container (a heterogeneous container is a container where the contained objects are of different types). There are two cases with heterogeneous containers. The first case occurs when all objects you want to store in a container are publicly derived from a common base class. You can then declare/define your container to hold pointers to the base class. You indirectly store a derived class object in a container by storing the object's address as an element in the container. You can then access objects in the container indirectly through the pointers (enjoying polymorphic behavior). If you need to know the exact type of the object in the container you can use dynamic_cast<> or typeid(). You'll probably need the virtual constructor (a.k.a. cloning) idiom to copy a container of disparate object types. The downside of this approach is that it makes memory management a little more problematic (who "owns" the pointed-to objects? if you delete these pointed-to objects when you destroy the container, how can you guarantee that no one else has a copy of one of these pointers? if you don't delete these pointed-to objects when you destroy the container, how can you be sure that someone else will eventually do the deleteing?). It also makes copying the container more complex (may actually break the container's copying functions since you don't want to copy the pointers, at least not when the container "owns" the pointed-to objects). The second case occurs when the object types are disjoint -- they do not share a common base class. The approach here is to use a handle class. The container is a container of handle objects (by value or by pointer, your choice; by value is easier). Each handle object knows how to "hold on to" (i.e. ,maintain a pointer to) one of the objects you want to put in the container. You can use either a single handle class with several different types of pointers as instance data, or a hierarchy of handle classes that shadow the various types you wish to contain (requires the container be of handle base class pointers). The downside of this approach is that it opens up the handle class(es) to maintenance every time you change the set of types that can be contained. The benefit is that you can use the handle class(es) to encapsulate most of the ugliness of memory management and object lifetime. Thus using handle objects may be beneficial even in the first case. [Adapted with permission from an email from Phil Staite, pstaite@vnet.ibm.com]. ============================================================================== [29.2] How can I insert/access/change elements from a linked list/hashtable/etc? I'll use an "inserting into a linked list" as a prototypical example. It's easy to allow insertion at the head and tail of the list, but limiting ourselves to these would produce a library that is too weak (a weak library is almost worse than no library). This answer will be a lot to swallow for novice C++'ers, so I'll give a couple of options. The first option is easiest; the second and third are better. 1. Empower the List with a "current location," and member functions such as advance(), backup(), atEnd(), atBegin(), getCurrElem(), setCurrElem(Elem), insertElem(Elem), and removeElem(). Although this works in small examples, the notion of a current position makes it difficult to access elements at two or more positions within the list (e.g., "for all pairs x,y do the following..."). 2. Remove the above member functions from List itself, and move them to a separate class, ListPosition. ListPosition would act as a "current position" within a list. This allows multiple positions within the same list. ListPosition would be a friend of class List, so List can hide its innards from the outside world (else the innards of List would have to be publicized via public member functions in List). Note: ListPosition can use operator overloading for things like advance() and backup(), since operator overloading is syntactic sugar for normal member functions. 3. Consider the entire iteration as an atomic event, and create a class template to embodies this event. This enhances performance by allowing the public access member functions (which may be virtual functions) to be avoided during the inner loop. Unfortunately you get extra object code in the application, since templates gain speed by duplicating code. For more, see [Koenig, "Templates as interfaces," JOOP, 4, 5 (Sept 91)], and [Stroustrup, "The C++ Programming Language Second Edition," under "Comparator"]. ============================================================================== [29.3] What's the idea behind templates? A template is a cookie-cutter that specifies how to cut cookies that all look pretty much the same (although the cookies can be made of various kinds of dough, they'll all have the same basic shape). In the same way, a class template is a cookie cutter to description of how to build a family of classes that all look basically the same, and a function template describes how to build a family of similar looking functions. class templates are often used to build type safe containers (although this only scratches the surface for how they can be used). ============================================================================== [29.4] What's the syntax / semantics for a "function template"? Consider this function that swaps its two integer arguments: void swap(int& x, int& y) { int tmp = x; x = y; y = tmp; } If we also had to swap floats, longs, Strings, Sets, and FileSystems, we'd get pretty tired of coding lines that look almost identical except for the type. Mindless repetition is an ideal job for a computer, hence a function template: template void swap(T& x, T& y) { T tmp = x; x = y; y = tmp; } Every time we used swap() with a given pair of types, the compiler will go to the above definition and will create yet another "template function" as an instantiation of the above. E.g., main() { int i,j; /*...*/ swap(i,j); // Instantiates a swap for int float a,b; /*...*/ swap(a,b); // Instantiates a swap for float char c,d; /*...*/ swap(c,d); // Instantiates a swap for char String s,t; /*...*/ swap(s,t); // Instantiates a swap for String } Note: A "template function" is the instantiation of a "function template". ============================================================================== [29.5] What's the syntax / semantics for a "class template"? Consider a container class of that acts like an array of integers: // This would go into a header file such as "Array.h" class Array { public: Array(int len=10) : len_(len), data_(new int[len]) { } ~Array() { delete [] data_; } int len() const { return len_; } const int& operator[](int i) const { data_[check(i)]; } int& operator[](int i) { data_[check(i)]; } Array(const Array&); Array& operator= (const Array&); private: int len_; int* data_; int check(int i) const { if (i < 0 || i >= len_) throw BoundsViol("Array", i, len_); return i; } }; Just as with swap() above, repeating the above over and over for Array of float, of char, of String, of Array-of-String, etc, will become tedious. // This would go into a header file such as "Array.h" template class Array { public: Array(int len=10) : len_(len), data_(new T[len]) { } ~Array() { delete [] data_; } int len() const { return len_; } const T& operator[](int i) const { data_[check(i)]; } T& operator[](int i) { data_[check(i)]; } Array(const Array&); Array& operator= (const Array&); private: int len_; T* data_; int check(int i) const { if (i < 0 || i >= len_) throw BoundsViol("Array", i, len_); return i; } }; Unlike template functions, template classes (instantiations of class templates) need to be explicit about the parameters over which they are instantiating: main() { Array ai; Array af; Array ac; Array as; Array< Array > aai; } Note the space between the two >'s in the last example. Without this space, the compiler would see a >> (right-shift) token instead of two >'s. ============================================================================== [29.6] What is a "parameterized type"? Another way to say, "class templates." A parameterized type is a type that is parameterized over another type or some value. List is a type (List) parameterized over another type (int). ============================================================================== [29.7] What is "genericity"? Yet another way to say, "class templates." Not to be confused with "generality" (which just means avoiding solutions which are overly specific), "genericity" means class templates. ============================================================================== SECTION [30]: Class libraries [30.1] Where can I get a copy of "STL"? "STL" is the "Standard Templates Library". You can get a copy from: An STL site: ftp://ftp.cs.rpi.edu/pub/stl STL HP official site: ftp://butler.hpl.hp.com/stl/ Mirror site in Europe: http://www.maths.warwick.ac.uk/ftp/mirrors/c++/stl/ STL code alternate: ftp://ftp.cs.rpi.edu/stl STL code + examples: http://www.cs.rpi.edu/~musser/stl.html STL hacks for GCC-2.6.3 are part of the GNU libg++ package 2.6.2.1 or later (and they may be in an earlier version as well). Thanks to Mike Lindner. ============================================================================== [30.2] Where can I get help on how to use STL? Kenny Zalewski's STL guide: http://www.cs.rpi.edu/projects/STL/htdocs/stl-new.html Dave Musser's STL guide: http://www.cs.rpi.edu/~musser/stl.html Mumit's STL Newbie's guide: http://www.xraylith.wisc.edu/~khan/software/stl/STL.newbie.html ============================================================================== [30.3] Where can I ftp the code that accompanies "Numerical Recipes"? This software is sold and therefore it would be illegal to provide it on the net. However, it's only about $30. ============================================================================== [30.4] Why is my executable so large? Many people are surprised by how big executables are, especially if the source code is trivial. For example, a simple "hello world" program can generate an executable that is larger than most people expect (40+K bytes). One reason executables can be large is that portions of the C++ runtime library gets linked with your program. How much gets linked in depends on how much of it you are using, and on how the implementer split up the library into pieces. For example, the library is quite large, and consists of numerous classes and virtual functions. Using any part of it might pull in nearly all of the code as a result of the interdependencies. You might be able to make your program smaller by using a dynamically-linked version of the library instead of the static version. You have to consult your compiler manuals or the vendor's technical support for a more detailed answer. ============================================================================== SECTION [31]: Compiler dependencies [31.1] GNU C++ (g++) produces big executables for tiny programs; Why? libg++ (the library used by g++) was probably compiled with debug info (-g). On some machines, recompiling libg++ without debugging can save lots of disk space (approximately 1 MB; the down-side: you'll be unable to trace into libg++ calls). Merely strip-ping the executable doesn't reclaim as much as recompiling without -g followed by subsequent strip-ping the resultant a.out's. Use size a.out to see how big the program code and data segments really are, rather than ls -s a.out which includes the symbol table. ============================================================================== [31.2] Is there a yacc-able C++ grammar? Jim Roskind is the author of a yacc grammar for C++. It's roughly compatible with the portion of the language implemented by USL cfront 2.0 (no templates, no exceptions, no run-time-type-identification). Jim's grammar deviates from C++ in a couple of minor-but-subtle ways. The grammar can be accessed on-line as follows: * ftp://ics.uci.edu/gnu/c++grammar2.0.tar.Z (ics.uci.edu is IP 128.195.1.1) * ftp://mach1.npac.syr.edu/pub/C++/c++grammar2.0.tar.Z (mach1.npac.syr.edu is IP 128.230.7.14) Note: I was told that these ftp addresses are no longer valid. Would someone please either confirm or deny this assertion, and would someone please let me know of an alternate address (cline@parashift.com). Thanks; Marshall Cline. ============================================================================== [31.3] What is C++ 1.2? 2.0? 2.1? 3.0? These are not versions of the language, but rather versions of cfront, which was the original C++ translator implemented by AT&T. It has become generally accepted to use these version numbers as if they were versions of the language itself. Very roughly speaking, these are the major features: * 2.0 includes multiple/virtual inheritance and pure virtual functions * 2.1 includes semi-nested classes and delete[] pointerToArray * 3.0 includes fully-nested classes, templates and i++ vs ++i * 4.0 will include exceptions ============================================================================== [31.4] If name mangling was standardized, could I link code compiled with compilers from different compiler vendors? Short answer: Probably not. In other words, some people would like to see name mangling standards incorporated into the proposed C++ ANSI standards in an attempt to avoiding having to purchase different versions of class libraries for different compiler vendors. However name mangling differences are one of the smallest differences between implementations, even on the same platform. Here is a partial list of other differences: * Number and type of hidden arguments to member functions. * is this handled specially? * where is the return-by-value pointer passed? * Assuming a vtable is used: * what is its contents and layout? * where/how is the adjustment to this made for multiple inheritance? * How are classes laid out, including: * location of base classes? * handling of virtual base classes? * location of vtable pointers, if vtables are used? * Calling convention for functions, including: * does caller or callee adjust the stack? * where are the actual parameters placed? * in what order are the actual parameters passed? * how are registers saved? * where does the return value go? * special rules for passing or returning structs or doubles? * special rules for saving registers when calling leaf functions? * How is the run-time-type-identification laid out? * How does the runtime exception handling system know which local objects need to be destructed during an exception throw? ============================================================================== SECTION [32]: Miscellaneous technical issues [32.1] Why are classes with static data members getting linker errors? static data members must be explicitly defined in exactly one module. E.g., class Fred { public: // ... private: static int i_; // Declares static data member Fred::i_ // ... }; The linker will holler at you ("Fred::i_ is not defined") unless you define (as opposed to declare) Fred::i_ in (exactly) one of your source files: int Fred::i_ = some_expression_evaluating_to_an_int; or: int Fred::i_; The usual place to define static data members of class Fred is file Fred.cpp (or Fred.C, etc; whatever filename extension you use). ============================================================================== [32.2] What's the difference between the keywords struct and class? The members and base classes of a struct are public by default, while in class, they default to private. Note: you should make your base classes explicitly public, private, or protected, rather than relying on the defaults. struct and class are otherwise functionally equivalent. ============================================================================== [32.3] Why can't I overload a function by its return type? If you declare both char f() and float f(), the compiler gives you an error message, since calling simply f() would be ambiguous. ============================================================================== [32.4] What is "persistence"? What is a "persistent object"? A persistent object can live after the program which created it has stopped. Persistent objects can even outlive different versions of the creating program, can outlive the disk system, the operating system, or even the hardware on which the OS was running when they were created. The challenge with persistent objects is to effectively store their member function code out on secondary storage along with their data bits (and the data bits and member function code of all member objects, and of all their member objects and base classes, etc). This is non-trivial when you have to do it yourself. In C++, you have to do it yourself. C++/OO databases can help hide the mechanism for all this. ============================================================================== [32.5] Why is floating point so inaccurate? Why doesn't this print 0.43? #include main() { float a = 1000.43; float b = 1000.0; cout << a - b << '\n'; } (On one C++ implementation, this prints 0.429993) Disclaimer: Frustration with rounding/truncation/approximation isn't really a C++ issue; it's a computer science issue. However, people keep asking about it on comp.lang.c++, so what follows is a nominal answer. Answer: Floating point is an approximation. The IEEE standard for 32 bit float supports 1 bit of sign, 8 bits of exponent, and 23 bits of mantissa. Since a normalized binary-point mantissa always has the form 1.xxxxx... the leading 1 is dropped and you get effectively 24 bits of mantissa. The number 1000.43 (and many, many others) is not exactly representable in float or double format. 1000.43 is actually represented as the following bitpattern (the "s" shows the position of the sign bit, the "e"s show the positions of the exponent bits, and the "m"s show the positions of the mantissa bits): seeeeeeeemmmmmmmmmmmmmmmmmmmmmmm 01000100011110100001101110000101 The shifted mantissa is 1111101000.01101110000101 or 1000 + 7045/16384. The fractional part is 0.429992675781. With 24 bits of mantissa you only get about 1 part in 16M of precision for float. The double type provides more precision (53 bits of mantissa). ============================================================================== SECTION [33]: Miscellaneous environmental issues [33.1] Is there a TeX or LaTeX macro that fixes the spacing on "C++"? Yes, here are three (the first prevents line breaks between the "C" and "++"): \def\CC{{C\nolinebreak[4]\hspace{-.05em}\raisebox{.4ex}{\tiny\bf ++}}} \def\CC{C\raise.22ex\hbox{{\footnotesize +}}\raise.22ex\hbox{\footnotesize +}} \def\CC{{C\hspace{-.05em}\raisebox{.4ex}{\tiny\bf ++}}} ============================================================================== [33.2] Where can I access C++2LaTeX, a LaTeX pretty printer for C++ source? ftp://ftp.german.eu.net/pub/packages/TeX/support/pretty/C++2LaTeX-3.02.tar.gz ============================================================================== [33.3] Where can I access "tgrind," a pretty printer for C++/C/etc source? "tgrind" reads a C++ source file, and spits out something that looks pretty on most Unix printers. It usually comes with the public distribution of TeX and LaTeX; look in the directory: "...tex82/contrib/van/tgrind". A more up-to-date version of tgrind by Jerry Leichter can be found on: ftp://venus.ycc.yale.edu/pub in [.TGRIND]. ============================================================================== [33.4] Is there a C++-mode for GNU emacs? If so, where can I get it? Yes, there is a C++-mode for GNU emacs. The latest and greatest version of C++-mode (and c-mode) is implemented in the file cc-mode.el. It is an extension of Detlef & Clamen's version. A version is included with emacs. Newer version are available from the elisp archives. ============================================================================== [33.5] Where can I get OS-specific FAQs answered (e.g., BC++, DOS, Windows, etc)? See one of the following: * comp.os.msdos.programmer * comp.windows.ms.programmer * comp.unix.programmer Note: If anyone has an email address for a BC++, VC++, or Semantic C++ bug list and/or discussion mailing list, please let me know how to subscribe (cline@parashift.com), and I'll mention it here. Thanks, Marshall Cline. ============================================================================== [33.6] Why does my DOS C++ program says "Sorry: floating point code not linked"? The compiler attempts to save space in the executable by not including the float-to-string format conversion routines unless they are necessary, but sometimes it guesses wrong, and gives you the above error message. You can fix this by (1) using instead of , or (2) by including the following function somewhere in your compilation (but don't call it!): static void dummyfloat(float *x) { float y; dummyfloat(&y); } See FAQ on stream I/O for more reasons to use vs . ============================================================================== [33.7] Why does my BC++ Windows app crash when I'm not running the BC45 IDE? If you're using BC++ for a Windows app, and it works OK as long as you have the BC45 IDE running, but when the BC45 IDE is shut down you get an exception during the creation of a window, then add the following line of code to the InitMainWindow() member function of your application (YourApp::InitMainWindow()): EnableBWCC(TRUE); ==============================================================================