From rifkin@cco.caltech.edu Sun Feb 13 05:14:53 1994 To: adam@vlsi.cs.caltech.edu Subject: C++ Faq 1 >Newsgroups: comp.lang.c++ >Path: nntp-server.caltech.edu!netline-fddi.jpl.nasa.gov!elroy.jpl.nasa.gov!usc!howland.reston.ans.net!europa.eng.gtefsd.com!news.umbc.edu!eff!news.kei.com!ub!clarkson!cheetah.ece.clarkson.edu!cline >From: cline@cheetah.ece.clarkson.edu (Marshall Cline) >Subject: C++ FAQ: posting #1/4 >Message-ID: <1994Feb11.210600.29984@news.clarkson.edu> >Followup-To: comp.lang.c++ >Summary: Please read this before posting to comp.lang.c++ >Sender: cline@sun.soe.clarkson.edu >Nntp-Posting-Host: cheetah.ece.clarkson.edu >Reply-To: cline@parashift.com (Marshall Cline) >Organization: Paradigm Shift, Inc (training/OOD/C++/libraries) >Date: Fri, 11 Feb 1994 21:06:00 GMT >Expires: Fri, 11 Mar 1994 21:06:00 GMT >Lines: 881 comp.lang.c++ Frequently Asked Questions list (with answers, fortunately). Copyright (C) 1991-93 Marshall P. Cline, Ph.D. Posting 1 of 4. ((((( THERE HAVE NOT BEEN ANY CHANGES SINCE LAST MONTH ))))) ============================================================================== SECTION 1: Introduction and table of contents ============================================================================== Document: Frequently-Asked-Questions for comp.lang.c++ Revision: Sep 13, 1993 Author: Marshall P. Cline, Ph.D. Paradigm Shift, Inc. One Park St. / Norwood, NY 13668 voice: 315-353-6100 fax: 315-353-6110 email: cline@parashift.com Copyright: Copyright (C), 1991-93 Marshall P. Cline, Ph.D. Permission to copy all or part of this work is granted, provided that the copies are not made or distributed for resale (except nominal copying fee may be charged), and provided that the NO WARRANTY, author-contact, and copyright notice are retained verbatim & are displayed conspicuously. If anyone needs other permissions that aren't covered by the above, please contact the author. 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. Availability: This is available via anonymous ftp from: sun.soe.clarkson.edu [128.153.12.3] in the file: pub/C++/FAQ Without FTP: You can also get it by sending electronic mail: | To: archive-server@sun.soe.clarkson.edu | Subject: send C++/FAQ This will help those who don't have ftp. (note: I hear the mail server is down; if you have problems, send details and I'll look into it). See also: comp.lang.c's FAQ appears at the beginning of every month in that newsgroup, and is maintained by Steve Summit (scs@adm.mit.edu). ============================================================================== SUBSECTION 1A: Table of Contents ============================================================================== ========== POSTING #1 ========== SECTION 1: Introduction and table of contents SUBSECTION 1A: Table of Contents SUBSECTION 1B: Nomenclature and Common Abbreviations SECTION 2: Environmental/managerial issues Q1: What is C++? What is OOP? Q2: What are some advantages of C++? Q3: Who uses C++? Q4: Are there any C++ standardization efforts underway? Q5: Where can I ftp a copy of the latest ANSI-C++ draft standard? Q6: Is C++ backward compatible with ANSI-C? Q7: How long does it take to learn C++? SECTION 3: Basics of the paradigm Q8: What is a class? Q9: What is an object? Q10: What is a reference? Q11: What happens if you assign to a reference? Q12: How can you reseat a reference to make it refer to a different object? Q13: When should I use references, and when should I use pointers? Q14: What are inline fns? What are their advantages? How are they declared? SECTION 4: Constructors and destructors Q15: What is a constructor? Why would I ever use one? Q16: How can I make a constructor call another constructor as a primitive? Q17: What are destructors really for? Why would I ever use them? SECTION 5: Operator overloading Q18: What is operator overloading? Q19: What operators can/cannot be overloaded? Q20: Can I create a `**' operator for `to-the-power-of' operations? SECTION 6: Friends Q21: What is a `friend'? Q22: Do `friends' violate encapsulation? Q23: What are some advantages/disadvantages of using friends? Q24: What does it mean that `friendship is neither inherited nor transitive'? Q25: When would I use a member function as opposed to a friend function? SECTION 7: Input/output via and Q26: How can I provide printing for a `class X'? Q27: Why should I use instead of the traditional ? Q28: Printf/scanf weren't broken; why `fix' them with ugly shift operators? ========== POSTING #2 ========== SECTION 8: Freestore management Q29: Does `delete ptr' delete the ptr or the pointed-to-data? Q30: Can I free() ptrs alloc'd with `new' or `delete' ptrs alloc'd w/ malloc()? Q31: Why should I use `new' instead of trustworthy old malloc()? Q32: Why doesn't C++ have a `realloc()' along with `new' and `delete'? Q33: How do I allocate / unallocate an array of things? Q34: What if I forget the `[]' when `delete'ing array allocated via `new X[n]'? SECTION 9: Debugging and error handling Q35: How can I handle a constructor that fails? Q36: How can I compile-out my debugging print statements? SECTION 10: Const correctness Q37: What is `const correctness'? Q38: Is `const correctness' a good goal? Q39: Is `const correctness' tedious? Q40: Should I try to get things const correct `sooner' or `later'? Q41: What is a `const member function'? Q42: What is an `inspector'? What is a `mutator'? Q43: What is `casting away const in an inspector' and why is it legal? Q44: But doesn't `cast away const' mean lost optimization opportunities? SECTION 11: Inheritance Q45: What is inheritance? Q46: Ok, ok, but what is inheritance? Q47: How do you express inheritance in C++? Q48: What is `incremental programming'? Q49: Should I pointer-cast from a derived class to its base class? Q50: Derived* --> Base* works ok; why doesn't Derived** --> Base** work? Q51: Does array-of-Derived is-NOT-a-kind-of array-of-Base mean arrays are bad? SUBSECTION 11A: Inheritance -- virtual functions Q52: What is a `virtual member function'? Q53: What is dynamic dispatch? Static dispatch? Q54: Can I override a non-virtual fn? Q55: Why do I get the warning "Derived::foo(int) hides Base::foo(double)"? SUBSECTION 11B: Inheritance -- conformance Q56: Can I `revoke' or `hide' public member fns inherited from my base class? Q57: Is a `Circle' a kind-of an `Ellipse'? Q58: Are there other options to the `Circle is/isnot kind-of Ellipse' dilemma? SUBSECTION 11C: Inheritance -- access rules Q59: Why can't I access `private' things in a base class from a derived class? Q60: What's the difference between `public:', `private:', and `protected:'? Q61: How can I protect subclasses from breaking when I change internal parts? SUBSECTION 11D: Inheritance -- constructors and destructors Q62: Why does base ctor get *base*'s virtual fn instead of the derived version? Q63: Does a derived class dtor need to explicitly call the base destructor? SUBSECTION 11E: Inheritance -- private and protected inheritance Q64: How do you express `private inheritance'? Q65: How are `private derivation' and `containment' similar? dissimilar? Q66: Should I pointer-cast from a `privately' derived class to its base class? Q67: Should I pointer-cast from a `protected' derived class to its base class? Q68: What are the access rules with `private' and `protected' inheritance? Q69: Do most C++ programmers use containment or private inheritance? SECTION 12: Abstraction Q70: What's the big deal of separating interface from implementation? Q71: How do I separate interface from implementation in C++ (like Modula-2)? Q72: What is an ABC (`abstract base class')? Q73: What is a `pure virtual' member function? Q74: How can I provide printing for an entire hierarchy rooted at `class X'? Q75: What is a `virtual destructor'? Q76: What is a `virtual constructor'? ========== POSTING #3 ========== SECTION 13: Style guidelines Q77: What are some good C++ coding standards? Q78: Are coding standards necessary? sufficient? Q79: Should our organization determine coding standards from our C experience? Q80: Should I declare locals in the middle of a fn or at the top? Q81: What source-file-name convention is best? `foo.C'? `foo.cc'? `foo.cpp'? Q82: What header-file-name convention is best? `foo.H'? `foo.hh'? `foo.hpp'? Q83: Are there any lint-like guidelines for C++? SECTION 14: C++/Smalltalk differences and keys to learning C++ Q84: Why does C++'s FAQ have a section on Smalltalk? Is this Smalltalk-bashing? Q85: What's the difference between C++ and Smalltalk? Q86: What is `static typing', and how is it similar/dissimilar to Smalltalk? Q87: Which is a better fit for C++: `static typing' or `dynamic typing'? Q88: How can you tell if you have a dynamically typed C++ class library? Q89: Will `standard C++' include any dynamic typing primitives? Q90: How do you use inheritance in C++, and is that different from Smalltalk? Q91: What are the practical consequences of diffs in Smalltalk/C++ inheritance? Q92: Do you need to learn a `pure' OOPL before you learn C++? Q93: What is the NIHCL? Where can I get it? SECTION 15: Reference and value semantics Q94: What is value and/or reference semantics, and which is best in C++? Q95: What is `virtual data', and how-can / why-would I use it in C++? Q96: What's the difference between virtual data and dynamic data? Q97: Should class subobjects be ptrs to freestore allocated objs, or contained? Q98: What are relative costs of the 3 performance hits of allocated subobjects? Q99: What is an `inline virtual member fn'? Are they ever actually `inlined'? Q100: Sounds like I should never use reference semantics, right? Q101: Does the poor performance of ref semantics mean I should pass-by-value? ========== POSTING #4 ========== SECTION 16: Linkage-to/relationship-with C Q102: How can I call a C function `f()' from C++ code? Q103: How can I create a C++ function `f()' that is callable by my C code? Q104: Why's the linker giving errors for C/C++ fns being called from C++/C fns? Q105: How can I pass an object of a C++ class to/from a C function? Q106: Can my C function access data in an object of a C++ class? Q107: Why do I feel like I'm `further from the machine' in C++ as opposed to C? SECTION 17: Pointers to member functions Q108: What is the type of `ptr-to-member-fn'? Is it diffn't from `ptr-to-fn'? Q109: How can I ensure `X's objects are only created with new, not on the stack? Q110: How do I pass a ptr to member fn to a signal handler,X event callback,etc? Q111: Why am I having trouble taking the address of a C++ function? Q112: How do I declare an array of pointers to member functions? SECTION 18: Container classes and templates Q113: How can I insert/access/change elements from a linked list/hashtable/etc? Q114: What's the idea behind `templates'? Q115: What's the syntax / semantics for a `function template'? Q116: What's the syntax / semantics for a `class template'? Q117: What is a `parameterized type'? Q118: What is `genericity'? Q119: How can I fake templates if I don't have a compiler that supports them? SECTION 19: Nuances of particular implementations Q120: Why don't variable arg lists work for C++ on a Sun SPARCstation? Q121: GNU C++ (g++) produces big executables for tiny programs; Why? Q122: Is there a yacc-able C++ grammar? Q123: What is C++ 1.2? 2.0? 2.1? 3.0? Q124: How does the lang accepted by cfront 3.0 differ from that accepted by 2.1? Q125: Why are exceptions going to be implemented after templates? Why not both? Q126: What was C++ 1.xx, and how is it different from the current C++ language? SECTION 20: Miscellaneous technical and environmental issues SUBSECTION 20A: Miscellaneous technical issues: Q127: Why are classes with static data members getting linker errors? Q128: What's the difference between the keywords struct and class? Q129: Why can't I overload a function by its return type? Q130: What is `persistence'? What is a `persistent object'? SUBSECTION 20B: Miscellaneous environmental issues: Q131: Is there a TeX or LaTeX macro that fixes the spacing on `C++'? Q132: Where can I access C++2LaTeX, a LaTeX pretty printer for C++ source? Q133: Where can I access `tgrind', a pretty printer for C++/C/etc source? Q134: Is there a C++-mode for GNU emacs? If so, where can I get it? Q135: What is `InterViews'? Q136: Where can I get OS-specific questions answered (ex:BC++,DOS,Windows,etc)? Q137: Why does my DOS C++ program says `Sorry: floating point code not linked'? ============================================================================== SUBSECTION 1B: Nomenclature and Common Abbreviations ============================================================================== Here are a few of the abbreviations/etc used in this article: term meaning ==== =========== ctor constructor copy-ctor copy constructor (also `X(const X&)', pronounced `X-X-ref') dtor destructor fn function fns functions ptr pointer, a C/C++ construct declared by: int * p; ref reference, a C++ construct declared by: int & r; OO object-oriented OOP object-oriented programming OOPL object-oriented programming language method an alternate term for `member function' ============================================================================== SECTION 2: Environmental/managerial issues ============================================================================== Q1: What is C++? What is OOP? C++ can be used simply as `a better C', but that is not its real advantage. C++ is an object-oriented programming language (OOPL). OOPLs appear to be the current `top shelf' in the development of programming languages that can manage the complexity of large software systems. Some OOP hype: software engineering is `failing' to provide the current users demands for large, complex software systems. But this `failure' is actually due to SE's *successes*. In other words, structured programming was developed to allow software engineers to design/build HUGE software systems (that's a success). When users saw how successful these systems were, they said, `More --- give me MOOORRRREEEE'. They wanted more power, more features, more flexibility. 100K line systems are almost commonplace nowadays, and they still want more. Structured programming techniques, some say, begin to break down around 100K lines (the complexity gives the design team too many headaches, and fixing one problem breaks 5 more, etc). So pragmatics demands a better paradigm than structured programming. Hence OO-design. ============================================================================== Q2: What are some advantages of C++? GROWTH OF C++: C++ is by far the most popular OOPL. Knowing C++ is a good resume-stuffer. But don't just use it as a better C, or you won't be using all its power. Like any quality tool, C++ must be used the way it was designed to be used. The number of C++ users is doubling every 7.5 to 9 months. This exponential growth can't continue forever(!), but it is becoming a significant chunk of the programming market (it's already the dominant OOPL). ENCAPSULATION: For those of you who aren't on a team constructing software mega-systems, what does C++ buy you? Here's a trivial example. Suppose you want a `Foible' data type. One style of doing this in `C' is to create a `Foible.h' file that holds the `public interface', then stick all the implementation into a `Foible.c' file. Encapsulation (hiding the details) can be achieved by making all data elements in `Foible.c' be `static'. But that means you only get one `Foible' in the entire system, which is ok if `Foible' is a Screen or perhaps a HardDisk, but is lousy if Foible is a complex number or a line on the screen, etc. Read on to see how it's done in `C' vs `C++'. MULTIPLE INSTANCES: The `C' solution to the above `multiple instances' problem is to wrap all the data members in a struct (like a Pascal `record'), then pass these structs around as if they were the `ComplexNumber' or whatever. But this loses encapsulation. Other techniques can be devised which allow both multiple instances and encapsulation, however these lose on other accounts (ex: typedef'ing `Foible' to be `void*' loses type safety, and wrapping a `void*' in the Foible struct loses an extra layer of indirection). So the `module' technique loses multiple instantiations, but the `struct' technique loses encapsulation. C++ allows you to combine the best of both worlds - you can have what amount to structs whose data is hidden. INLINE FUNCTION CALLS: The `encapsulated C' solution above requires a function call to access even trivial fields of the data type (if you allowed direct access to the struct's fields, the underlying data structure would become virtually impossible to change since too many pieces of code would *rely* on it being the `old' way). Function call overhead is small, but can add up. C++ provides a solution by allowing 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: For the `ComplexNumber' example, you want to be able to use it in an expression `just as if' it was a builtin type like int or float. C++ allows you to overload operators, so you can tell the compiler what it means for two complex numbers to be added, subtracted, multiplied, etc. This gives you: z0 = (z1 + z2) * z3 / z4; Furthermore you might want string1+string2 to mean string concatenation, etc. One of the goals of C++ is to make user defined types `look like' builtin types. You can even have `smart pointers', which means a pointer `p' could actually be a user defined data type that `points' to a disk record (for example). `Dereferencing' such a pointer (ex: i=*p;) means ``seek to the location on disk where p `points' and return its value''. Also statements like p->field=27; can store things on disk, etc. If later on you find you can fit the entire pointed-to data structure in memory, you just change the user-defined pseudo-pointer type and recompile. All the code that used these `pseudo pointers' doesn't need to be changed at all. 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 especially twice as much code to maintain). C++ provides a much cleaner solution: inheritance. You say `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: The real power of OOP 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 (ie: a InvertableStack is-a Stack that can also invert itself). Polymorphism is easiest to understand from an example, so here's a `classic': a graphical draw 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). Ex: if a Shape is picked by a mouse, the Shape might get dragged across the screen and placed into a new location. Polymorphism allows the code to work correctly even if the compiler only knows that the parameter is a `Shape' without knowing the exact kind of Shape it is. Furthermore suppose the `pick_and_drag(Shape*) function just mentioned 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 Hexagons, even though the Hexagon 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!) ============================================================================== Q3: Who uses C++? A: Lots and lots of companies and government sites. Lots. Statistically, 20 to 30 people will consider themselves to be new C++ programmers before you finish reading the responses to these FAQs. ============================================================================== Q4: Are there any C++ standardization efforts underway? A: Yes; ANSI (American) and ISO (International) groups are working closely with each other. `X3J16' is the name of the ANSI-C++ committee. `WG21' is the name of ISO's C++ standards group. The committees are using the `ARM' as a base document: `Annotated C++ Reference Manual', Ellis and Stroustrup, Addison/Wesley. ISBN 0-201-51459-1 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, , ... and a lot of users and smaller companies. About 70 people attend each ANSI C++ meeting. People come from USA, UK, Japan, Germany, Sweden, Denmark, France, ... (all have `local' committees sending official representatives and conducting `local' meetings). Optimistically the standard might be finished by 1995-6 time frame (this is fast for a proper standards process). ============================================================================== Q5: Where can I ftp a copy of the latest ANSI-C++ draft standard? A: You can't. ANSI standards and/or drafts are NOT available in machine readable form. >>>>UPDATED 9/93 You can get a paper copy by sending a request to: Standards Secretariat CBEMA/X3 1250 I Street NW Suite 200 Washington, DC 20005 Ask for the latest version of `Working Paper for Draft Proposed American National Standard for Information Systems -- Programming Language C++'. The last known phone number: 202-626-5738. The last known price is $25. ============================================================================== Q6: Is C++ backward compatible with ANSI-C? A: Almost. C++ is as close as possible to compatible with ANSI-C but no closer. In practice, the major difference is that C++ requires prototypes, and that `f()' declares a function that takes no parameters, while ANSI-C rules state that `f()' declares a function that takes any number of parameters of any type. There are some very subtle differences as well, like the sizeof a char literal being equal to the sizeof a char (in ANSI-C, sizeof('x') is the sizeof an int). Structure `tags' are in the same namespace as other names in C++, but C++ has some warts to take care of backward compatibility here. ============================================================================== Q7: How long does it take to learn C++? A: I and others teach standard industry `short courses' (for those not familiar with these, you pack a university semester course into one 40hr work-week), and have found them successful. However mastery takes experience, and there's no substitute for time. Laboratory time is essential for any OOP course, since it allows concepts to `gel'. Generally people start out wondering why the company has devoted a full 5 days to something as trivial as another programming language. Then about half way through, they realize they're not being taught just a new syntax, but an entirely different way of thinking and programming and designing and . . . . Then they begin to feel dumb, since they can't quite grasp what is being said. Then they get mad and wonder why the course isn't taught in two or three weeks instead. Finally about Wednesday afternoon the lights go `clink', and their faces brighten, and they `get it'. By Friday, they've had numerous laboratory `experiments' and they've seen both sides of reusable components (both how to code *from* reuse, and how to code *for* reuse). It's different in every time I teach, but the `reuse' aspect is rewarding, since it has a large potential to improve software production's overall economics. It takes 9 months to `master' C++/OOP. Less if there is already a body of experts and code that programmers have regular access to, more if there isn't a `good' general purpose C++ class library available. ============================================================================== SECTION 3: Basics of the paradigm ============================================================================== Q8: What is a class? A: A class defines a data type, much like a struct would be in C. In a CompSci sense, a type consists of two things: a set of values *and* a set of operations which operate on those values. Thus `int' all by itself isn't a true `type' until you add operations like `add two ints' or `int*int', 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. From a C language perspective, a `class' is a `struct' whose members default to `private'. ============================================================================== Q9: What is an object? A: An object is a region of storage with associated semantics. After the declaration `int i;', we say that `i is an object of type int'. In C++/OOP, `object' is usually used to mean `an instance of a class'. Thus a class defines the behavior of possibly many objects (instances). ============================================================================== Q10: What is a reference? A: A reference is an alias (an alternate name) for an object. It is frequently used for pass-by-reference; ex: 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. The effect is as if you used the C style pass-by-pointer, but the `&' is moved from the caller into the callee. Pascal enthusiasts will recognize this as a VAR param. ============================================================================== Q11: What happens if you assign to a reference? A: Assigning to a reference changes the referred-to value, thus a ref is an `Lvalue' (something that can appear on the `L'eft-hand-side of an assignment statement) for the referred-to value. This insight can be pushed a bit farther by allowing references to be *returned*, thus allowing function calls on the left hand side of an assignment stmt. ============================================================================== Q12: How can you reseat a reference to make it refer to a different object? A: 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; you can't separate the reference from the referred-to-object. Ex: `&ref' is the address of the referred-to-object, not of the reference itself. ============================================================================== Q13: When should I use references, and when should I use pointers? A: Old line C programmers sometimes don't like references since the reference semantics they provide isn't *explicit* in the caller's code. After a bit of C++ experience, however, one quickly realizes this `information hiding' is an asset rather than a liability. In particular, reuse-centered OOP tends to migrate the level of abstraction away from the language of the machine toward the language of the problem. References are usually preferred over ptrs whenever you don't need `reseating' (see early question on `How can you reseat a reference'). This usually means that references are most useful in a class' public interface. References then 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 ptr). ============================================================================== Q14: What are inline fns? What are their advantages? How are they declared? A: An inline function is a function which gets textually inserted by the compiler, much like a macro. Like macros, performance is improved by avoiding the overhead of the call itself, and (especially!) by the compiler being able to optimize *through* the call (`procedural integration'). Unlike macros, arguments to inline fns are always evaluated exactly once, so the `call' is semantically like a regular function call only faster. Also unlike macros, argument types are checked and necessary conversions are performed correctly. Beware that overuse of inline functions can cause code bloat, which can in turn have a negative performance impact in paging environments. They are declared by using the `inline' keyword when the function is defined: inline void f(int i, char c) { /*...*/ } //an inline function or by including the function definition itself within a class: class X { public: void f(int i, char c) { /*...*/ } //inline function within a class }; or by defining the member function as `inline' outside the class: class X { public: void f(int i, char c); }; //... inline void X::f(int i, char c) {/*...*/} //inline fn outside the class Generally speaking, a function cannot be defined as `inline' after it has been called. Inline functions should be defined in a header file, with `outlined' functions appearing in a `.C' file (or .cpp, etc; see question on file naming conventions). ============================================================================== SECTION 4: Constructors and destructors ============================================================================== Q15: What is a constructor? Why would I ever use one? A: Objects should establish and maintain their own internal coherence. The `maintaining' part is done by ensuring self-consistency is restored after any operation completes (ex: by incrementing the link count after adding a new link to a linked list). The part about `establishing coherence' is the job of a constructor. Constructors are like `init functions'; they build a valid object. The constructor turns a pile of incoherent arbitrary bits into a living object. Minimally it initializes any internally used fields that are needed, but it may also allocate resources (memory, files, semaphores, sockets, ...). A constructor is like a `factory': it builds objects from dust. `ctor' is a typical abbreviation for constructor. ============================================================================== Q16: How can I make a constructor call another constructor as a primitive? A: You can't. Use an `init()' member function instead (often `private:'). ============================================================================== Q17: What are destructors really for? Why would I ever use them? A: Destructors are used to release any resources allocated by the object's constructor. Ex: a Lock class might lock a semaphore, and the destructor will release that semaphore. The usual `resource' being acquired in a constructor (and subsequently released in a destructor) is dynamically allocated memory. `dtor' is a typical abbreviation for destructor ============================================================================== SECTION 5: Operator overloading ============================================================================== Q18: What is operator overloading? A: Operator overloading allows the basic C/C++ operators to have user-defined meanings on user-defined types (classes). They are syntactic sugar for equivalent function calls; ex: class X { //... public: //... }; X add(X, X); //a top-level function that adds two X's X mul(X, X); //a top-level function that multiplies two X's X f(X a, X b, X c) { return add(add(mul(a,b), mul(b,c)), mul(c,a)); } Now merely replace `add' with `operator+' and `mul' with `operator*': X operator+(X, X); //a top-level function that adds two X's X operator*(X, X); //a top-level function that multiplies two X's X f(X a, X b, X c) { return a*b + b*c + c*a; } ============================================================================== Q19: What operators can/cannot be overloaded? A: 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 Vec { int data[100]; public: int& elem(unsigned i) { if (i>99) error(); return data[i]; } }; main() { Vec v; v.elem(10) = 42; v.elem(12) += v.elem(13); } Now simply replace `elem' with `operator[]': class Vec { int data[100]; public: int& operator[](unsigned i) { if (i>99) error(); return data[i]; } }; //^^^^^^^^^^--formerly `elem' main() { Vec v; v[10] = 42; v[12] += v[13]; } ============================================================================== Q20: Can I create a `**' operator for `to-the-power-of' operations? A: No. 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 doubt the wisdom of this approach, consider the following code: x = y ** z; Looks like your power operator? Nope. z may be a ptr, so this is actually: x = y * (*z); Lexical analysis groups characters into tokens at the lowest level of the compiler's operations, so adding new operators would present an implementation nightmare (not to mention the increased maintenance cost to read the code!). Besides, operator overloading is just syntactic sugar for function calls. It does not add fundamental power to the language (although this particular syntactic sugar can be very sweet, it is not fundamentally necessary). I suggest you overload `pow(base,exponent)', for which a double precision version is provided by the ANSI-C library. By the way: operator^ looks like a good candidate for to-the-power-of, but it has neither the proper precedence nor associativity. ============================================================================== SECTION 6: Friends ============================================================================== Q21: What is a `friend'? A: Friends can be either functions or other classes. The class grants friends access privileges. Normally a developer has political and technical control over both the class, its members, and its friends (that way you avoid political problems when you want to update a portion, since you don't have to get permission from the present owner of the other piece(s)). ============================================================================== Q22: Do `friends' violate encapsulation? A: Friends can be looked at three ways: (1) they are not class members and they therefore violate encapsulation of the class members by their mere existence, (2) a class' friends are absorbed into that class' encapsulation barrier, and (3) any time anyone wants to do anything tricky they textedit the header file and add a new friend so they can get right in there and fiddle 'dem bits. No one argues that (3) is a Good Thing, and for good reasons. The arguments for (1) always boil down to the rather arbitrary and somewhat naive view that a class' member functions `should' be the *only* functions inside a class' encapsulation barrier. I have not seen this view bear fruit by enhancing software quality. On the other hand, I have seen (2) bear fruit by lowering the *overall* coupling in a software system. Reason: friends can be used as `liaisons' to provide safe, screened access for the whole world, perhaps in a way that the class syntactically or semantically isn't able to do for itself. Conclusion: friend functions are merely a syntactic variant of a class' public access functions. When used in this manner, they don't violate encapsulation any more than a member function violates encapsulation. Thus a class' friends and members *are* the encapsulation barrier, as defined by the class itself. I've actually seen the `friends always violate encapsulation' view *destroy* encapsulation: programmers who have been taught that friends are inherently evil want to avoid them, but they have another class or fn that needs access to some internal detail in the class, so they provide a member fn which exposes the class' internal details to the PUBLIC! Private decisions should stay private, and only those inside your encapsulation barrier (your members, friends, and [for `protected' things] your subclasses) should have access. ============================================================================== Q23: What are some advantages/disadvantages of using friends? A: The advantage of using friends is generally syntactic. Ie: both a member fn and a friend are equally privileged (100% vested), but a friend function can be called like f(obj), where a member is called like obj.f(). When it's not for syntactic reasons (which is not a `bad' reason -- making an abstraction's syntax more readable lowers maintenance costs!), friends are used when two or more classes are designed to be more tightly coupled than you want for `joe public' (ex: you want to allow class `ListIter' to have more privilege with class `List' than you want to give to `main()'). Friends have three disadvantages. The first disadvantage is that they add to the global namespace. In contrast, the namespace of member functions is buried within the class, reducing the chance for namespace collisions for functions. The second disadvantage is that they aren't inherited. That is, the `friendship privilege' isn't inherited. This is actually an advantage when it comes to encapsulation. Ex: I may declare you as my friend, but that doesn't mean I trust your kids. The third disadvantage is that they don't bind dynamically. Ie: they don't respond to polymorphism. There are no virtual friends; if you need one, have a friend call a hidden (usually `protected:') virtual member fn. Friends that take a ptr/ref to a class can also take a ptr/ref to a publically derived class object, so they act as if they are inherited, but the friendship *rights* are not inherited (the friend of a base has no special access to a class derived from that base). ============================================================================== Q24: What does it mean that `friendship is neither inherited nor transitive'? A: This is speaking of the access privileges granted when a class declares a friend. The access privilege of friendship is not inherited: * I may trust you, but I don't necessarily trust your kids. * My friends aren't necessarily friends of my kids. * Class `Base' declares f() to be a friend, but f() has no special access rights with class `Derived'. The access privilege of friendship is not transitive: * I may trust you, and you may trust Sam, but that doesn't necessarily mean that I trust Sam. * A friend of a friend is not necessarily a friend. ============================================================================== Q25: When would I use a member function as opposed to a friend function? A: Use a member when you can, and a friend when you have to. Like in real life, my family members have certain privileges that my friends do not have (ex: my family members inherit from me, but my friends do not, etc). To grant privileged access to a function, you need either a friend or a member; there is no additional loss of encapsulation one way or the other. Sometimes friends are syntactically better (ex: in class `X', friend fns allow the `X' param to be second, while members require it to be first). Another good use of friend functions are the binary infix arithmetic operators. Ex: `aComplex + aComplex' probably should be defined as a friend rather than a member, since you want to allow `aFloat + aComplex' as well (members don't allow promotion of the left hand arg, since that would change the class of the object that is the recipient of the member function invocation). ============================================================================== SECTION 7: Input/output via and ============================================================================== Q26: How can I provide printing for a `class X'? A: Provide a friend operator<<: class X { public: friend ostream& operator<< (ostream& o, const X& x) { return o << x.i; } //... private: int i; //just for illustration }; We use a friend rather than a member since the `X' parameter is 2nd, not 1st. Input is similar, but the signature is: istream& operator>> (istream& i, X& x); //not `const X& x' !! ============================================================================== Q27: Why should I use instead of the traditional ? A: See next question. ============================================================================== Q28: Printf/scanf weren't broken; why `fix' them with ugly shift operators? A: The overloaded shift operator syntax is strange at first sight, but it quickly grows on you. However syntax is just syntax; the real issues are deeper. 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 (left/right shift) is, relative to C (printf/scanf): * type safe -- type of object being I/O'd is known statically by the compiler rather than via dynamically tested '%' fields * less error prone -- redundant info has greater chance to get things wrong C++ I/O has no redundant '%' tokens to get right * faster -- printf is basically an `interpreter' of a tiny language whose constructs mainly include '%' fields. the proper low-level routine is chosen at runtime based on these fields. C++ I/O picks these routines statically based on actual types of the args * extensible -- perhaps most important of all, the C++ I/O mechanism is extensible to new user-defined data types (imagine the chaos if everyone was simultaneously adding new incompatible '%' fields to printf and scanf?!). Remember: we want to make user-defined types (classes) look and act like `built-in' types. * subclassable -- ostream and istream (the C++ replacements for FILE*) 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. Ex: you can have a `stream' that writes to a memory area (incore formatting provided by the standard class `strstream'), or you could have it use the stdio buffers, or [you name it...]. -- Marshall Cline -- Marshall P. Cline, Ph.D. / Paradigm Shift Inc / PO Box 5108 / Potsdam NY 13676 cline@parashift.com / 315-353-6100 / FAX: 315-353-6110