Tuesday, July 29, 2008

C++ INTERVIEW QUESTIONS

C++

Q1: What is C++? What is OOP?
A: 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++?
A: 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: Does C++ run on machine `X' running operating system `Y'?
A: Most likely, `Yes'.

See the next question for a few specifics. Finding vendors isn't always easy.
If you're still stuck after reading this FAQ, try comp.lang.c++ and/or BIX.
==============================================================================
Q5: What C++ compilers are available?
A: Lots. Here are a few:

* `Cfront' is USL's compiler. It compiles to C, so it is `technically' a
translator rather than native code compiler, but that doesn't make much
difference in practice (think of C as an assembly language). Many hardware
vendors bundle and/or sell a `cfront-based' C++ compiler.
* GNU C++ is freely copyable under the Free Software Foundation `copyleft'.
Usually called g++, it is available via anonymous ftp from prep.ai.mit.edu.
It is supported by Cygnus (contact tiemann@cygnus.com).
* Borland C++ (BC++) and Turbo C++ (TC++) are available from Borland Int'l.
It is available for DOS; an OS/2 2.0 product has been announced.
* Zortech C++ (ZTC++) is available from Zortech Int'l. DOS and OS/2.
* Glockenspiel C++ is a DOS port of cfront; also runs on some Un*x platforms.
* Saber C++ is a Un*x based interpreter/compiler programmer's workbench.
* ObjectCenter is a Un*x based interpreter/compiler programmer's workbench
distributed by CenterLine (formerly Saber Software). 617/498-3000
* Saber C++ is the former name for ObjectCenter (`Saber' became `CenterLine').
* Oregon C++; native-code compiler and source-level debugger; TauMetric Corp;
800-874-8501; Sun4, DECstation, Sun3, HP9000/300 & 400, i386/i486SV, VAX/VMS
* Green Hills C++ (sorry, no further information)
* Symantec's Think-C for Macintosh (5.0 supports many of the features of C++)
800-228-4122 or 408-253-9600.
* Intek (sorry, no further information)
* MPW C++ is a cfront 2.1 port for Apple from APDA=Apple Progmr's/Developer's
Assoc: USA:800-282-2732, Canada:800-637-0029, International:408-562-3910
* ObjectWorks\C++; ParcPlace; Un*x based interpreter/compiler programmers w.b.
* Comeau Computing has a cfront 2.1-based compiler for Amiga, DOS, and Unix.
* SAS Institute (was Lattice, Inc) has a cfront 1.2-based compiler for Amiga.
==============================================================================
Q6: Is there a translator that turns C++ code into C code?
A: Yes, there are many. USL produces such a compiler called `cfront' (if you
think of C as an assembly language, then it's a `compiler'; if you think of C
as a high level language, then it's a `translator'; technically cfront is a
`compiler front end'). Many companies port and resell this product.
==============================================================================
Q7: 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.

They are using the `Annotated C++ Reference Manual' (`ARM' for short) as a base
document. See below under `Books' for how to get the ARM.

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, here>, ... 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 1994 time frame (this is fast
for a proper standards process).
==============================================================================
Q8: 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.

You can get a paper copy by sending a request to:
Standards Secretariat
CBEMA
311 First St NW, Suite 500
Washington, DC 20001
Ask for the latest version of `Working Paper for Draft Proposed American
National Standard for Information Systems -- Programming Language C++'.
==============================================================================
Q9: 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.
==============================================================================
Q10: What books are available for C++?
A: Lots, with more just about every other week. Here are a few in no
particular order (comments are my own):

`The C++ Programming Language, second edition', Stroustrup, Addison/Wesley
A rich, in-depth intro text; covers rudiments of OOD as well as OOP ISBN 0-201-53992-6
`A C++ Primer, 2nd edition', Lippman, Addison/Wesley 1st ed.
Considered std intro-C++ text; does not assume C; has some OOD ISBN 0-201-54848-8
`Annotated C++ Reference Manual', Ellis and Stroustrup, Addison/Wesley
Heavy reading; definitely not for beginners; gives *ALL* the details.
ISBN 0-201-51459-1
`Advanced C++ Programming Styles and Idioms', Coplien, Addison-Wesley, 1992
ref-counting, wrappers, functionoids, `Self'/`Smalltalk' styles, etc ISBN 0-201-54855-0
`A C++ Toolkit', Shapiro, Prentice Hall
Provides many small stand-alone classes; code is publically usable ISBN 0-13-127663-8
`Mastering C++', Horstmann, Wiley Wiley
Hasn't sent me one to review yet, but I hear it's great
`Teach Yourself C++', Stevens, MIS Press
An easy-to-read short book for C++ beginners ISBN 1-558-28027-8
`A C++ Primer, first edition', Lippman, Addison/Wesley
Slightly out-of-date; solidly reference quality wrt the language proper ISBN 0-201-16487-6
`Programming in C++', Dewhurst and Stark, Prentice Hall
How-to-use C++, shows many idioms of the language
`Using C++', Eckel, McGraw-Hill
Shows some of the ways C++ can be used as a better C; MS-DOS
`Data Abstraction and OO Programming in C++', Gorlen/Orlow/Plexico, Wiley
Describes how to use NIHCL (see question on `NIHCL') ISBN 0-471-92346-X
`An Intro to OO Programming', Tim Budd, Addison-Wesley, 1991
Covers OOP in general; compares/contrasts several OOPLs including C++
ISBN 0-201-54709-0
`Object-Oriented Design with Applications', Grady Booch, Benjamin/Cummings,1991
Excellent 1st book on OO design; read on Classification and Abstraction
ISBN 0-8053-0091-0
`Object-Orientation: Concepts, Languages, Databases, User interfaces',
Khoshafian and Abnous, J.Wiley, 1990
ISBN 0-471-51801-8
`The Waite Group's C++ Programming', Berry
`An Introduction to Object-Oriented Programming and C++', Weiner & Pinson, A/W
`Object-Oriented Program Design with Examples in C++', Mullin, Addison-Wesley
`Hands-on C++ Programming', Isaac and Miller, Addison-Wesley
`C++ for C Programmers', Pohl, Benjamin/Cummings
`The C++ Programming Language, first edition', Stroustrup, Addison/Wesley
Out of date but a classic; get it to find out where the language `was'
ISBN 0-201-12078-X
`The C++ Answer Book', Hansen, Addison/Wesley
Answers to the exercises in Stroustrup's first ed; solid `how-to' text
ISBN 0-201-11497-6
`Turbo C++ DiskTutor', Greg Voss and Paul Chui, McGraw-Hill
ISBN 0-07-881526-6
`Object-Oriented Software Construction', Meyer, Prentice Hall
Chaps 1-4 are about OOP in general; the rest is about Eiffel language
ISBN 0-13-629049-3

Conference proceedings:
Proceedings of the `OOPSLA' conferences
Proceedings of the `C++ At Work' conferences
Proceedings of the `USENIX C++' conferences

Periodicals:
The C++ Report
Journal of Object-Oriented Programming
The C++ Journal
the working papers of the ANSI-C++ committee

Usenix newsgroups and mailing lists:
comp.lang.c++
comp.std.c++
comp.object
BIX
Turbo-C++ mailing list
==============================================================================
Q11: 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 generally the most rewarding, since it has
the greatest potential to improve software production's overall economics.

Full semester courses have the same overall contact hours (14wks * 3hrs/wk is
around 40hrs), but the slower rate allows students to retain more as well as to
go through more material. For example, I taught the equivalent of my `C++ as
an OOPL' course, and portions of my `OO Design Methodology' course, in a single
semester graduate course. Both courses take roughly a week when taught in the
condensed style.

It takes 6 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.
==============================================================================
==============================================================================
Q12: 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'.
==============================================================================
Q13: 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).
==============================================================================
Q14: 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.
==============================================================================
Q15: 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.
==============================================================================
Q16: 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.
==============================================================================
Q17: 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 nil ptr (0) this special significance (references
should always alias *objects*, not a dereferenced nil ptr).
==============================================================================
Q18: 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).
==============================================================================
==============================================================================
Q19: 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.
==============================================================================
Q20: 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
==============================================================================
==============================================================================
Q21: 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;
}
==============================================================================
Q22: 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];
}
==============================================================================
Q23: 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.
==============================================================================
==============================================================================
Q24: What is a `friend'?
A: Friends can be either functions or other classes. The class grants friends
unlimited access privileges.
==============================================================================
Q25: 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.
==============================================================================
Q26: 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).
==============================================================================
Q27: 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.
==============================================================================
Q28: 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 message).
==============================================================================
==============================================================================
Q29: How can I provide printing for a `class X'?
A: Provide a friend operator<<: class X { int i; //just for illustration public: friend ostream& operator<<(ostream& o, const X& x) { return o <<>> (istream& i, X& x); //not `const X& x' !!
==============================================================================
Q30: Why should I use instead of the traditional ?
A: See next question.
==============================================================================
Q31: 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...].
==============================================================================
==============================================================================
Q32: Does `delete ptr' delete the ptr or the pointed-to-data?
A: The pointed-to-data.

When you read `delete p', say to yourself `delete the thing pointed to by p'.
One could argue that the keyword is misleading, but the same abuse of English
occurs when `free'ing the memory pointed to by a ptr in C:
free(ptr); /* why not `free_the_stuff_pointed_to_by(p)' ?? */
==============================================================================
Q33: Can I free() ptrs alloc'd with `new' or `delete' ptrs alloc'd w/ malloc()?
A: No. You should not mix C and C++ heap management.
==============================================================================
Q34: Why should I use `new' instead of trustworthy old malloc()?
A: malloc() doesn't call constructors, and free() doesn't call destructors.
Besides, malloc() isn't type safe, since it returns a `void*' rather than a ptr
of the right type (ANSI-C punches a hole in its typing system to make it possible to use malloc() without pointer casting the return value, but C++
closes that hole). Besides, `new' is an operator that can be overridden by a
class, while `malloc' is not overridable on a per-class basis (ie: even if the
class doesn't have a constructor, allocating via malloc might do inappropriate
things if the freestore operations have been overridden).
==============================================================================
Q35: Why doesn't C++ have a `realloc()' along with `new' and `delete'?
A: Because realloc() does *bitwise* copies (when it has to copy), which will
tear most C++ objects to shreds. C++ objects know how to copy themselves. They use their own copy constructor or assignment operator (depending on whether we're copying into a previously unused space [copy-ctor] or a previous object [assignment op]).

Moral: never use realloc() on objects of a class. Let the class copy its own
objects.
==============================================================================
Q36: How do I allocate / unallocate an array of things?
A: Use new[] and delete[]:

Thing* p = new Thing[100];
//...
delete [] p; //older compilers require you to use `delete [100] p'

Any time you allocate an array of things (ie: any time you use the `[...]' in
the `new' expression) you *!*MUST*!* use the `[]' in the `delete' statement.

The fact that there is no syntactic difference between a ptr to a thing and a
ptr to an array of things is an artifact we inherited from C.
==============================================================================
Q37: What if I forget the `[]' when `delete'ing array allocated via `new X[n]'?
A: Life as we know it suddenly comes to a catastrophic end.

It is the programmer's --not the compiler's-- responsibility to get the
connection between new[] and delete[] correct. If you get it wrong, neither a
compile-time nor a run-time error message will be generated by the compiler.

Depending on the implementation, the results *may* be harmless if the class
whose objects are being `delete'd has no destructor, but this is implementation
dependent. If the class *does* have a destructor, only the first object in the
array (the one at `ptr[0]') will be destructed properly; the rest will simply
be abandoned. If the destructor releases memory, this will be a memory leak;
if it closes files or unlocks semaphores or other environmental actions, system
integrity may be fractured.
==============================================================================
Q38: What's the best way to create a `#define macro' for `NULL' in C++?
A: The best way is: don't do it.

The most portable way to compare against the nil ptr is to compare against `0'.
Some programmers use a #define to set NULL to `0', but that can conflict with
the way the standard libraries #define NULL. There is no portable way to define a `const' ptr called `NULL' that can be compared against any arbitrary ptr -- the literal `0' is acceptable for this however.
==============================================================================
==============================================================================
Q39: How can I handle a constructor that fails?
A: Constructors (ctors) do not return any values, so no returned error code is possible. There are many possibilities for how to handle this, one of which is to set the object itself into a `half baked' state by setting an internal status bit. Naturally there should be a query (`inspector') method to check this bit, allowing clients to discover whether they have a live object. Other member functions should check this bit, and either do a no-op (or perhaps something more obnoxious such as `abort()') if the object isn't really alive. Check out how the iostreams package handles attempts to open nonexistent/illegal files for an example of prior art.

One more thing: you might want to store information indicating *why* the
failure took place in addition to a `failure bit'.

When real exceptions come to C++, they will provide a better strategy; the best
technique will generally be to throw an exception.
==============================================================================
Q40: How can I compile-out my debugging print statements?
A: This will NOT work, since comments are parsed before the macro is expanded:
#ifdef DEBUG_ON
#define DBG
#else
#define DBG //
#endif
DBG cout << i="3," j="4);" i="3;" j="4);"> Base* works ok; why doesn't Derived** --> Base** work?
A: A C++ compiler will allow a Derived* to masquerade as a Base*, since a Derived object is a kind of a Base object. However passing a Derived** as a
Base** (or otherwise trying to convert a Derived** to a Base**) is (correctly)
flagged as an error.

An array of Deriveds is-NOT-a-kind-of-an array of Bases. I like to use the
following example in my C++ training sessions:
`A Bag of Apples is *NOT* a Bag of Fruit'

Suppose a `Bag' could be passed to a function taking a Bag such as `f(Bag& b)'. But `f()' can insert *any* kind of Fruit into the Bag. Imagine the surprise on the caller's face when he gets the Bag back only to find it has a Banana in it!

Here's another example I use:
A ParkingLot of Car is-NOT-a-kind-of-a ParkingLot of Vehicle (otherwise you could pass a ParkingLot* as a ParkingLot*, and the called fn could park an EighteenWheeler in a ParkingLot designed for Cars!)

These improper things are violations of `contravariance' (that's the scientific
glue that holds OOP together). C++ enforces contravariance, so you should trust your compiler at moments like these. Contravariance is more solid than our fickle intuition.
==============================================================================
Q55: Does array-of-Derived is-NOT-a-kind-of array-of-Base mean arrays are bad?
A: Yes, `arrays are evil' (jest kidd'n :-).

There's a very subtle problem with using raw built-in arrays. Consider this:

void f(Base* array_of_Base)
{
array_of_Base[3].memberfn();
}

main()
{
Derived array_of_Derived[10];
f(array_of_Derived);
}

This is perfectly type-safe, since a D* is-a B*, but it is horrendously evil,
since Derived might be larger than Base, so the array index in f() not only isn't type safe, it's not even going to be pointing at a real object! In general it'll be pointing somewhere into the innards of some poor D.

The fundamental problem here is that C++ cannot distinguish a ptr-to-a-thing from a ptr-to-an-array-of-things (witness the required `[]' in `delete[]' when
deleting an array as another example of how these different kinds of ptrs are
actually different). Naturally C++ `inherited' this feature from C.

This underscores the advantage of using an array-like *class* instead of using
a raw array (the above problem would have been properly trapped as an error if
we had used a `Vec' rather than a `T[]'; ex: you cannot pass a Vec to `f(Vec& v)').

==============================================================================
SUBSECTION: Inheritance -- virtual functions
==============================================================================

Q56: What is a `virtual member function'?
A: A virtual member function is a member fn preceded by the keyword `virtual'.

It has the effect of allowing derived classes to replace the implementation of
the fn. Furthermore the replacement is always called whenever the object in
question is actually of the derived class. The impact is that algorithms in
the base class can be replaced in the derived class without affecting the
operation of the base class. The replacement can be either full or partial,
since the derived class operation can invoke the base class version if desired.

This is discussed further below.
==============================================================================
Q57: What is dynamic dispatch? Static dispatch?
A: In the following discussion, `ptr' means either a pointer or a reference.

When you have a ptr to an object, there are two distinct types in question: the
static type of the ptr, and the dynamic type of the pointed-to object (the object may actually be of a class that is derived from the class of the ptr).

The `legality' of the call is checked based on the static type of the ptr,
which gives us static type safety (if the type of the ptr can handle the member
fn, certainly the pointed-to object can handle it as well, since the pointed-to
object is of a class that is derived from the ptr's class).

Suppose ptr's type is `List' and the pointed-to object's type is `FastList'.
Suppose the fn `len()' is provided in `List' and overridden in `FastList'. The
question is: which function should actually be invoked: the function attached
to the pointer's type (`List::len()') or the function attached to the object
itself (`FastList::len()')?

If `len()' is a virtual function, as it would be in the above case, the fn
attached to the object is invoked. This is called `dynamic binding', since the
actual code being called is determined dynamically (at run time).

On the other hand, if `len()' were non-virtual, the dispatch would be resolved
statically to the fn attached to the ptr's class.
==============================================================================
Q58: Can I override a non-virtual fn?
A: Yes but you shouldn't. The only time you should do this is to get around
the `hiding rule' (see below, and ARM sect.13.1), and the overridden definition
should be textually identical to the base class' version.

The above advice will keep you out of trouble, but it is a bit too strong.
Experienced C++ programmers will sometimes override a non-virtual fn for
efficiency, and will provide an alternate implementation which makes better use
of the derived class' resources. However the client-visible effects must be
*identical*, since non-virtual fns are dispatched based on the static type of
the ptr/ref rather than the dynamic type of the pointed-to/referenced object.
==============================================================================
Q59: Why do I get the warning "Derived::foo(int) hides Base::foo(double)" ?
A: A member function in a derived class will *hide* all member functions of the
same name in the base class, *not* overload them, even if Base::foo(double) is
virtual (see ARM 13.1). This is done because it was felt that programmers would, for example, call a_derived.foo(1) and expect Derived::foo(double) to be called. If you define any member function with the name `foo' in a derived class, you must redefine in class Derived all other Base::foo()'s that you wish to allow access from a Derived object (which generally means all of them; you should [generally] *not* try to hide inherited public member functions since it breaks the `conformance' of the derived class with respect to the base class).

class Base {
public:
void foo(int);
};

class Derived : public Base {
public:
void foo(double);
void foo(int i) { Base::foo(i); } // <-- override it with itself }; ============================================================================== SUBSECTION: Inheritance -- conformance ============================================================================== Q60: Can I `revoke' or `hide' public member fns inherited from my base class? A: Never never never do this. Never. NEVER! This is an all-too-common design error. It usually stems from muddy thinking (but sometimes it stems from a very difficult design that doesn't seem to yield anything elegant). ============================================================================== Q61: Is a `Circle' a kind-of an `Ellipse'? A: Depends on what you claim an Ellipse can do. Ex: suppose Ellipse has a `scale(x,y)' method, which is meaningless for Circle. There are no easy options at this point, but the worst of all possible worlds is to keep muddling along and hope that no one stubs their toes over the bad design (if we're serious about reuse, we should fix our mistakes rather than leave them to a future generation). If an Ellipse can do something a Circle can't, a Circle can't be a kind of Ellipse. Should there be any other relationship between Circle and Ellipse? Here are two reasonable options: * make Circle and Ellipse completely unrelated classes. * derive Circle and Ellipse from a base class representing `Ellipses that can't *necessarily* perform an unequal-scale operation'. In the first case, Ellipse could be derived from class `AsymmetricShape' (with scale(x,y) being introduced in AsymmetricShape), and Circle should be derived from `SymmetricShape', which has a scale(factor) member fn. In the second case, we could create class `Oval' that has only an equal scale operation, then derive both `Ellipse' and `Circle' from Oval, where Ellipse --but not Circle-- adds the unequal scale operation (see the `hiding rule' for a caveat if the same method name `scale' is used for both unequal and equal scale operations). In any event, we could create an operation to create an Ellipse whose size et al are the same as a given Circle, but this would be a constructive operation (ie: it would create a brand new object, like converting an int to a float, but unlike passing a reference to a Circle as if it were a ref to an Ellipse). Example: class Ellipse : public Oval { //... ^^^^^^^^^^^^^---- or whatever public: Ellipse(const Circle& circle); }; Or: class Circle /*...*/ { public: operator Ellipse() const; //... }; ============================================================================== Q62: Are there other options to the `Circle is/isnot kind-of Ellipse' dilemma? A: There appear to be 2 other options (but read below for why these are poor): * redefine Circle::scale(x,y) to throw an exception or call `abort()'. * redefine Circle::scale(x,y) to be a no-op, or to scale both dimensions by the average of the parameters (or some other arbitrary value). Throwing an exception will `surprise' clients. You claimed that a Circle was actually a kind of an Ellipse, so they pass a Circle off to `f(Ellipse& e)'. The author of this function read the contract for Ellipse very carefully, and scale(x,y) is definitely allowed. Yet when f() innocently calls e.scale(5,3), it kills him! Conclusion: you lied; what you gave them was distinctly *not* an Ellipse. In the second case, you'll find it to be very difficult to write a meaningful semantic specification (a `contract') for Ellipse::scale(x,y). You'd like to be able to say it scales the x-axis by `x' and the y-axis by `y', but the best you can say is `it may do what you expect, or it may do nothing, or it may scale both x and y even if you asked it to only scale the x (ex: `scale(2,1)'). Since you've diluted the contract into dribble, the client can't rely on any meaningful behavior, so the whole hierarchy 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). ============================================================================== SUBSECTION: Inheritance -- access rules ============================================================================== Q63: Why can't I access `private' things in a base class from a derived class? A: 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. ============================================================================== Q64: What's the difference between `public:', `private:', and `protected:'? A: `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 fn) accessible to subclasses. Thus members defined in the `private:' section of class X are accessible only to the member functions and friends of class X; members defined in the `public:' section are accessible by everyone; `protected:' members are accessible by members fns and friends of class X, as well as member fns of subclasses of X. ============================================================================== Q65: How can I protect subclasses from breaking when I change internal parts? A: You can make your software more resilient to internal changes by realizing a class has two distinct interfaces for two distinct sets of clients: * its `public:' interface serves unrelated classes * its `protected:' interface serves derived classes A class that is intended to have a long and happy life can hide its physical bits in its `private:' part, then put `protected:' inline access functions to these data. The private bits can change, but if the protected access fns are stable, subclasses (ie: derived classes) won't break (though they'll need to be recompiled after a change to the base class). ============================================================================== SUBSECTION: Inheritance -- constructors and destructors ============================================================================== Q66: Why does base ctor get *base*'s virtual fn instead of the derived version? ie. when constructing an obj of class `Derived', Base::Base() invokes `virt()'. `Derived::virt()' exists (an override of `Base::virt()'), yet `Base::virt()' gets control rather than the `Derived' version; why? A: A constructor turns raw bits into a living object. Until the ctor has finished, you don't have a complete `object'. In particular, while the base class' ctor is working, the object isn't yet a Derived class object, so the call of the base class' virtual fn defn is correct. Similarly dtors turn a living object into raw bits (they `blow it to bits'), so the object is no longer a Derived during Base's dtor. Therefore the same thing happens: when Base::~Base() calls `virt()', Base::virt() gets control, not the Derived::virt() override. (Think of what would happen if the Derived fn touched a subobject from the Derived class, and you'll quickly see the wisdom of the approach). ============================================================================== Q67: Does a derived class dtor need to explicitly call the base destructor? A: No, you never need to explicitly call a dtor (where `never' means `rarely'). ie: you only have to have an explicit dtor call in rather esoteric situations such as destroying an object created by the `placement new operator'. In the usual case, a derived class' dtor (whether you explicitly define one or not) automatically invokes the dtors for subobjects and base class(es). Subobjects are destroyed immediately after the derived class' destructor body (`{...}'), and base classes are destroyed immediately after subobjects. Subobjects are destroyed from bottom to top in the lexical order they appear within a class, and base classes from right to left in the order of the base-class-list. ============================================================================== SUBSECTION: Inheritance -- private and protected inheritance ============================================================================== Q68: How do you express `private inheritance'? A: When you use `: private' instead of `: public'. Ex: class Foo : private Bar { //... }; ============================================================================== Q69: How are `private derivation' and `containment' similar? dissimilar? A: Private derivation can be thought of as a syntactic variant of containment (has-a). Ex: it is NOT true that a privately derived is-a-kind-of-a Base: With private derivation: class Car : private Engine {/*...*/}; //a Car is NOT a-kind-of Engine Similarly: class Car { Engine e; /*...*/ }; //normal containment There are several similarities between these two forms of containment: * in both cases there is exactly one Engine subobject contained in a Car * in neither case can clients (outsiders) convert a Car* to an Engine* There are also several distinctions: * the second form is needed if you want to contain several subobjects * the first form can introduce unnecessary multiple inheritance * the first form allows members of Car to convert a Car* to an Engine* * the first form allows access to the `protected' members of the base class * the first form allows Car to override Engine's virtual functions. Private inheritance is almost always used for the last item: to gain access into the `protected:' members of the base class. ============================================================================== Q70: Should I pointer-cast from a `privately' derived class to its base class? A: The short answer: no, but yes too (better read the long answer!) From `inside' the privately derived class (ie: in the body of members or friends of the 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 and doesn't need a cast. From `outside' the privately derived class, the relationship to `Base' is a `private' decision of `PrivatelyDer', so the conversion requires a cast. Clients should not exercise this cast, since private derivation is a private implementation decision of the privately derived class, and the coercion will fail after the privately derived class privately chooses to change this private implementation decision. Bottom line: only a class and its friends have the right to convert a ptr to a derived class into a ptr to its private base class. They don't need a cast, since the relationship with the base class is accessible to them. No one else can convert such ptrs without pointer-casts, so no one else should. ============================================================================== Q71: Should I pointer-cast from a `protected' derived class to its base class? A: Protected inheritance is similar to private inheritance; the answer is `no'. class Car : protected Engine {/*...*/}; //protected inheritance In `private' inheritance, only the class itself (and its friends) can know about the relation to the base class (the relationship to the base class is a `private' decision). In protected inheritance, the relationship with the base class is a `protected' decision, so *subclasses* of the `protectedly' derived class can also know about and exploit this relationship. This is a `for better *and* for worse' situation: future changes to `protected' decisions have further consequences than changing a private decision (in this case, the class, its friends, *and* subclasses, sub- sub- classes, etc, all need to be examined for dependencies upon the relationship to the base class). However it is also for better, in that subclasses have the ability to exploit the relationship. The existence of protected inheritance in C++ is debated in some circles. ============================================================================== Q72: What are the access rules with `private' and `protected' inheritance? A: Take these classes as examples: class B { /*...*/ }; class D_priv : private B { /*...*/ }; class D_prot : protected B { /*...*/ }; class D_publ : public B { /*...*/ }; class Client { B b; /*...*/ }; Public and protected parts of B are `private' in D_priv, and are `protected' in D_prot. In D_publ, public parts of B are public (D_prot is-a-kind-of-a B), and protected parts of B remain protected in D_publ. Naturally *none* of the subclasses can access anything that is private in B. Class `Client' can't even access the protected parts of B (ie: it's `sealed off'). It is often the case that you want to make some but not all inherited member functions public in privately/protectedly derived classes. Ex: to make member fn B::f(int,char,float) public in D_prot, you would say: class D_prot : protected B { //... public: B::f; //note: not B::f(int,char,float) }; There are limitations to this technique (can't distinguish overloaded names, and you can't make a feature that was `protected' in the base `public' in the derived). Where necessary, you can get around these by a call-through fn: class D_prot : protected B { public: short f(int i, char c, float f) { return B::f(i,c,f); } }; ============================================================================== Q73: Do most C++ programmers use containment or private inheritance? A: Short answer: generalizations are always wrong (that's a generalization :-). The long answer is another generalization: most C++ programmers use regular containment (also called `composition' or `aggregation') more often than private inheritance. The usual reason is that they don't *want* to have access to the internals of too many other classes. Private inheritance is not evil; it's just more expensive to maintain, since it increases the number of classes that have access to `internal' parts of other classes (coupling). The `protected' parts of a class are more likely to change than the `public' parts. ============================================================================== ============================================================================== Q74: What's the big deal of separating interface from implementation? A: Separating interface from implementation is a key to reusable software. 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 resources of more expensive people (for better and worse, most companies separate `designers' from `coders'). Since they're so valuable, they should be protected from being tarnished by data structures and other artifacts of the implementation (any data structures you put in a class can never be `revoked' by a derived class, which is why you want to `separate' the interface from the implementation). ============================================================================== Q75: How do I separate interface from implementation in C++ (like Modula-2)? A: Short answer: use an ABC (see next question for what an ABC is). ============================================================================== Q76: What is an ABC (`abstract base class')? A: An 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, and volkswaggon beetles too. The problem is that the term `Vehicle' is an abstract concept; you can't build one until you know what kind of vehicle to build. In C++, you'd make Vehicle be an ABC, with Bicycle, SpaceShuttle, etc, being subclasses (an OceanLiner is-a-kind-of-a Vehicle). In real-world OOP, ABCs show up all over the place. Technically, an ABC is a class that has one or more pure virtual member functions (see next question). You cannot make an object (instance) of an ABC. ============================================================================== Q77: What is a `pure virtual' member function? A: Some member functions exist in concept, but can't have any actual defn. Ex: Suppose I asked you to draw a Shape at location (x,y) that has size 7.2. You'd ask me `what kind of shape should I draw', since circles, squares, hexagons, etc, are drawn differently. In C++, we indicate the existence of the `draw()' method, but we recognize it can only be defined in subclasses: class Shape { public: virtual void draw() const = 0; //... ^^^--- `=0' means it is `pure virtual' }; This pure virtual makes `Shape' an ABC. The `const' says that invoking the `draw()' method won't change the Shape object (ie: it won't move around on the screen, change sizes, etc). If you want, you can think of it as if the code were at the nil pointer. Pure virtuals allow you to express the idea that any actual object created from a [concrete] class derived from the ABC *will* have the indicated member fn, but we simply don't have enough information to actually *define* it yet. They allow separation of interface from implementation, which ultimately allows functionally equivalent subclasses to be produced that can `compete' in a free market sense (a technical version of `market driven economics'). ============================================================================== Q78: How can I provide printing for an entire hierarchy rooted at `class X'? A: Provide a friend operator<< const =" 0;" const =" 0;" s2 =" s.clone();" s3 =" s.fresh();" endif ="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="" operator="(const" operator="(const" this ="="" a="a+b'" op="'" ans =" a;" 10 ="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="="=""> #2(is-a) alone (ex:you intend to override most/all inherited code)
--> both #2(is-a) and #1(code-sharing)
but one should never Never use the above form of inheritance to mean
--> #1(code-sharing) alone (ex: D really *isn't* a B, but...)

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'). 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; ex: you
can make something that `is-a Stack' yet doesn't inherit from `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.
==============================================================================
Q95: What are the practical consequences of diffs in Smalltalk/C++ inheritance?
A: Since Smalltalk lets you make a subtype without making a subclass, one can
be very carefree in putting data (bits, representation, data structure) into a
class (ex: you might put a linked list into a Stack class). After all, if
someone wants something that an array-based-Stack, they don't have to inherit
from Stack; they can go off and make effectively a stand-alone class (they
might even *inherit* from an Array class, even though they're not-a-kind-of-
Array!).

In C++, you can't be nearly as carefree. Since only mechanism (method code),
but not representation (data bits) can be overridden in subclasses, you're
usually better off *not* putting the data structure in a class. This leads to
the concept of Abstract Base Classes (ABCs), which are discussed in a separate
question. You can change the algorithm but NOT the data structure. Bits are
forever.

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'.

Note that C++ compilers uphold the is-a semantic constraint only with `public'
inheritance. Neither containment (has-a), nor private or protected inheritance
implies conformance.
==============================================================================
Q96: Do you need to learn a `pure' OOPL before you learn C++?
A: The short answer is, No.

The medium answer length answer is: learning some `pure' OOPLs may *hurt*
rather than help.

The long answer is: read the previous questions on the difference between C++
and Smalltalk (the usual `pure' OOPL being discussed; `pure' means everything
is an object of some class; `hybrid' [like C++] means things like int, char,
and float are not instances of a class, hence aren't subclassable).

The `purity' of the OOPL doesn't make the transition to C++ any more or less
difficult; it is the weak typing and improper inheritance that is so hard to
get. I've taught numerous people C++ with a Smalltalk background, and they
usually have just as hard a time as those who've never seen inheritance before.
In fact, my personal observation is that those with extensive experience with a
weakly typed OOPL (usually but not always Smalltalk) have a *harder* time,
since it's harder to *unlearn* habits than it is to learn the statically typed
way from the beginning.
==============================================================================
Q97: What is the NIHCL? Where can I get it?
A: NIHCL stands for `national-institute-of-health's-class-library'.
it can be acquired via anonymous ftp from [128.231.128.251]
in the file pub/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 weak typing helps (ex: persistent objects). There are also
places where the weak typing it introduces create tension with the underlying
statically typed language.

A draft version of the 250pp reference manual is included with version 3.10
(gnu emacs TeX-info format). It is not available via uucp, or via regular mail
on tape, disk, paper, etc (at least not from Keith Gorlen).

See previous questions on Smalltalk for more.
==============================================================================
==============================================================================
Q98: What is value and/or reference semantics, and which is best in C++?
A: With reference semantics, assignment is a pointer-copy (ie: 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 ptr-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*. Smalltalk and Eiffel and CLOS and most other OOPLs force reference
semantics; you must use an alternate syntax to copy the value (clone, shallowCopy, deepCopy, etc), but even then, these languages ensure that any
name of an object is actually a *pointer* to that object (Eiffel's `expanded'
classes allow a supplier-side work-around).

There are many pros to reference semantics, including flexibility and dynamic
binding (you get dynamic binding in C++ only when you pass by ptr or pass by
ref, not when you pass by value).

There are also many pros to value semantics, including speed. `Speed' seems
like an odd benefit to for a feature that requires an object (vs a ptr) 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 ptr to
an object.

There are three cases when you have an actual object as opposed to a pointer to
an object: local vars, global/static vars, and fully contained subobjects in a
class. The most common & most important of these is the last (`containment').

More info about copy-vs-reference semantics is given in the next questions.
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 questions, you'll get a warped perspective.

Assignment has other issues (ex: shallow vs deep copy) which are not covered
here.
==============================================================================
Q99: What is `virtual data', and how-can / why-would I use it in C++?
A: Virtual data isn't strictly a `part' of C++, however it can be simulated.
It's not entirely pretty, but it works. First we'll cover what it is and how
to simulate it, then conclude with why it isn't `part' of C++.

Consider classes Vec (like an array of int) and SVec (a stretchable Vec; ie:
SVec overrides operator[] to automatically stretch the number of elements
whenever a large index is encountered). SVec inherits from Vec. Naturally
Vec's subscript operator is virtual.

Now consider a VStack class (Vec-based-Stack). Naturally this Stack has a
capacity limited by the fixed number of elements in the underlying Vec data
structure. Then someone comes along and wants an SVStack class (SVec based
Stack). For some reason, they don't want to merely modify VStack (say, because
there are many users already using it).

The obvious choice then would be to inherit SVStack from VStack, however
then there'd be *two* Vecs in an SVStack object (one explicitly in VStack,
the other as the base class subobject in the SVec which is explicitly in
the SVStack). That's a lot of extra baggage. There are at least 2 solns:
* break the is-a link between SVStack and VStack, text-copy the code from
VStack and manually change `Vec' to `SVec'.
* activate some sort of virtual data, so subclasses can change the
class of subobjects.

To effect virtual data, we need to change the Vec subobject from a physically
contained subobject into a ptr pointing to a dynamically allocated subobject:

_____original_____ _____to_support_virtual_data_____
class VStack { class VStack {
protected: protected:
Vec v; //where data stored Vec& v; //where data is stored
int sp; //stack pointer int sp; //stack pointer
public: public:
VStack(int cap=10) VStack(int cap=10)
: v(cap), sp(0) { } : v(*new Vec(cap)), sp(0) { }
//FREESTORE
void push(int x) {v[sp++]=x;} void push(int x) {v[sp++]=x;} //no change
int pop() {return v[--sp];} int pop() {return v[--sp];} //no change
~VStack() { } //unnecessary ~VStack() {delete &v;} //NECESSARY
}; };

Now the subclass has a shot at overriding the defn of the object referred to as
`v'. Ex: basically SVStack merely needs to bind a new SVec to `v', rather than
letting VStack bind the Vec. However classes can only initialize their *own*
subobjects in an init-list. Even if I had used a ptr rather than a ref, VStack
must be prevented from allocating its own `Vec'. The way we do this is to add
another ctor to VStack that takes a Vec& and does *not* allocate a Vec:
class VStack {
protected:
VStack(Vec& vv) : v(vv), sp(0) { } //`protected' constructor!
//... //(prevents public
access)
};

That's all there is to it! Now the subclass (SVStack) can be defined as:
class SVStack : public VStack {
public:
SVStack(int init_cap=10) : VStack(*new SVec(init_cap)) { }
};

Pros: * implementation of SVStack is a one-liner
* SVStack shares code with VStack

Cons: * extra layer of indirection to access the Vec
* extra freestore allocations (both new and delete)
* extra dynamic binding (reason given in next question)

We succeeded at making *our* job easier as implementor of SVStack, but all
clients pay for it. It wouldn't be so bad if clients of SVStack paid for it,
after all, they chose to use SVStack (you pay for it if you use it). However
the `optimization' made the users of the plain VStack pay as well!

See the question after the next to find out how much the client's `pay'. Also:
*PLEASE* read the few questions that follow the next one too (YOU WILL NOT GET
A BALANCED PERSPECTIVE WITHOUT THE OTHERS).
==============================================================================
Q100: What's the difference between virtual data and dynamic data?
A: The easiest way to see the distinction is by an analogy with `virtual fns':
A virtual member fn means the declaration (signature) must stay the same in
subclasses, but the defn (body) can be overridden. The overriddenness of an
inherited member fn 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 defns of the member fn.

Now go back and re-read the previous paragraph, but make these substitutions:
`member fn' --> `subobject'
`signature' --> `type'
`body' --> `exact class'
After this, you'll have a working defn of virtual data.

`Per-object member fns' (a member fn `f()' which is potentially different in
any given instance of an object) could be handled by burying a function ptr in
the object, then setting the (const) fn ptr during construction.

`Dynamic member fns' (member fns which change dynamically over time) could also
be handled by function ptrs, but this time the fn ptr would not be const.

In the same way, there are three distinct concepts for data members:
* virtual data: the defn (`class') of the subobject is overridable in
subclasses provided its declaration (`type') remains the same, and this
overriddenness is a static property of the [sub]class.
* per-object-data: any given object of a class can instantiate a different
conformal (same type) subobject upon initialization (usually a `wrapper'
object), and the exact class of the subobject is a static property of the
object that wraps it.
* dynamic-data: the subobject'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 ptr 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.
==============================================================================
Q101: Should class subobjects be ptrs to freestore allocated objs, or contained?
A: Usually your subobjects should actually be `contained' in the aggregate
class (but not always; `wrapper' objects are a good example of where you want a
a ptr/ref; also the N-to-1-uses-a relationship needs something like a ptr/ref).

There are three reasons why fully contained subobjects have better performance
than ptrs to freestore allocated subobjects:
* extra layer to indirection every time you need to access subobject
* extra freestore allocations (`new' in ctor, `delete' in dtor)
* extra dynamic binding (reason given later in this question)
==============================================================================
Q102: What are relative costs of the 3 performance hits of allocated subobjects?
A: The three performance hits are enumerated in the previous question:
* By itself, an extra layer of indirection is small potatoes.
* Freestore allocations can be a big problem (standard malloc's performance
degrades with more small freestore allocations; OO s/w can easily become
`freestore bound' unless you're careful).
* Extra dynamic binding comes from having a ptr rather than an object.
Whenever the C++ compiler can know an object's *exact* class, virtual fn
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 subobjects.

Thus fully-contained subobjects allow significant optimizations that wouldn't
be possible under the `subobjects-by-ptr' approach (this is the main reason
that languages which enforce reference-semantics have `inherent' performance
problems).
==============================================================================
Q103: What is an `inline virtual member fn'? Are they ever actually `inlined'?
A: A inline virtual member fn is a member fn that is inline and virtual :-).
The second question is much harder to answer. The short answer is `Yes, but'.

A virtual call (msg dispatch) via a ptr or ref is always resolved dynamically
(at run-time). In these situations, the call is never inlined, since the actual code may be from a derived class that was created after the caller was compiled.

The difference between a regular fn call and a virtual fn call is rather small.
In C++, the cost of dispatching is rarely a problem. But the lack of inlining
in any language can be very Very significant. Ex: simple experiments will show
the difference to get as bad as an order of magnitude (for zillions of calls to
insignificant member fns, loss of inlining virtual fns can result in 25X speed
degradation! [Doug Lea, `Customization in C++', proc Usenix C++ 1990]).

This is why endless debates over the actual number of clock cycles required to
do a virtual call in language/compiler X on machine Y are largely meaningless.
Ie: many language implementation vendors make a big stink about how good their
msg dispatch strategy is, but if these implementations don't *inline* method
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 QUESTIONS TO SEE THE OTHER SIDE OF THIS COIN!
==============================================================================
Q104: Sounds like I should never use reference semantics, right?
A: Wrong.

Reference semantics is A Good Thing. We can't live without pointers. We just
don't want our s/w to be One Gigantic Pointer. In C++, you can pick and choose
where you want reference semantics (ptrs/refs) 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'. These combine to indicate reference semantics should be used
for problem-space objects (Booch says `Entity Abstractions'; see on `Books').

The question arises: is reference semantics likely to cause a performance
problem in these `entity abstractions'? The key insight in answering this
question is that the relative interaction frequency is much lower for problem
skin abstractions than for low level server objects.

Thus we have an *ideal* situation in C++: we can 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. The result is very likely to be that
the highest frequency objects will end up with value semantics. Thus we
install flexibility only where it doesn't hurt us, and 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.
That's the investment-price you pay for a powerful tool.

<<<>>>
==============================================================================
Q105: Does the poor performance of ref semantics mean I should pass-by-value?
A: No. In fact, `NO!' :-)

The previous questions were talking about *subobjects*, not parameters. Pass-
by-value is usually a bad idea when mixed with inheritance (larger subclass
objects get `sliced' when passed by value as a base class object). Generally,
objects that are part of an inheritance hierarchy should be passed by ref or by
ptr, but not by value, since only then do you get the (desired) dynamic
binding.

Unless compelling reasons are given to the contrary, subobjects should be by
value and parameters should be by reference. The discussion in the previous
few questions indicates some of the `compelling reasons' for when subobjects
should be by reference.
==============================================================================
==============================================================================
Q106: How can I call a C function `f()' from C++ code?
A: Tell the C++ compiler that it is a C function: extern "C" void f();
Be sure to include the full function prototype. A block of many C functions
can be grouped via braces, as in:
extern "C" {
void* malloc(size_t);
char* strcpy(char* dest, const char* src);
int printf(const char* fmt, ...);
}
==============================================================================
Q107: How can I create a C++ function `f()' that is callable by my C code?
A: Use the same `extern "C" f()' construct as detailed in the previous
question, only then proceed to actually define the function in your C++ module.
The compiler will ensure that the external information sent to the linker uses
C calling conventions and name mangling (ex: preceded by a single underscore).
Obviously you can't make several overloaded fns simultaneously callable by a C
program, since name overloading isn't supported by C.

Caveats and implementation dependencies:
* your `main()' should be compiled with your C++ compiler.
* your C++ compiler should direct the linking process.
==============================================================================
Q108: Why's the linker giving errors for C/C++ fns being called from C++/C fns?
A: See the previous two questions on how to use `extern "C"'.
==============================================================================
Q109: How can I pass an object of a C++ class to/from a C function?
A: Here's an example of one that will work (be sure to read the tail of this
answer which details when such a scheme will *not* work):

/****** C/C++ header file: X.h ******/
#ifdef __cplusplus /*`__cplusplus' is #defined iff compiler is C++*/
extern "C" {
#endif

#ifdef __STDC__
extern int c_fn(struct X*); /* ANSI-C prototypes */
extern struct X* cplusplus_callback_fn(struct X*);
#else
extern int c_fn(); /* K&R style */
extern struct X* cplusplus_callback_fn();
#endif

#ifdef __cplusplus
}
#endif

#ifdef __cplusplus
class X {
int a;
public:
X();
void frob(int);
};
#endif

Then, in file `X.C':
//X.C
#include "X.h"
X::X() : a(0) { }
void X::frob(int aa) { a = aa; }
X* cplusplus_callback_fn(X* x)
{
x->frob(123);
return x;
}

In C++ file `main.C':
#include "X.h"
int main()
{
X x;
c_fn(&x);
return 0;
}

Finally, in a C file `c-fn.c':
/* C source file c-fn.c */
#include "X.h"
int c_fn(struct X* x)
{
if (cplusplus_callback_fn(x))
do_one_thing();
else
do_something_else();
return something();
}

Passing ptrs to C++ objects to/from C fns will FAIL if you pass and get back
something that isn't *exactly* the same pointer, such as passing a base class
ptr and receiving a derived class ptr (this fails when multiple inheritance is
involved, since C fails to do pointer-conversion properly).
==============================================================================
Q110: Can my C function access data in an object of a C++ class?
A: Sometimes.

(First read the previous question 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 fns)
* has all its data in the same access-level section (private/protected/public)
* has no fully-contained subobjects with virtual fns

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 you can often (but less than always) assume a `void*' appears in
the object at the location of the first virtual function. This is trickier,
since the first virtual function is often in a different access specifier
section than the data members. Even the use of a single pointer is not
required by the language (but this is the way `everyone' does it).

If the class has any virtual base classes, it is 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 DAG), with the rest of the object's
parts appearing in the normal order. Every class that has V as a virtual base
class actually has a *pointer* to the V part of the final object.
==============================================================================
Q111: Why do I feel like I'm `further from the machine' in C++ as opposed to C?
A: Because you are. Being an OOPL, C++ allows you to directly model the
problem domain itself (obviously OOD is more complex than this, but a good
start at `finding the objects' is to model the nouns in the problem domain).
By modeling the problem domain, the system interacts 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++; overloaded operators are a case in point. Old
line C programmers (such as many of us once were) are often ambivalent about
this feature, but soon we realize that it provides a level of abstraction and
economy of expression which lowers maintenance costs without destroying runtime
performance.

Naturally you can write assembly code in any language; using 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 good programmers to write good
programs.
==============================================================================
==============================================================================
Q112: What is the type of `ptr-to-member-fn'? Is it diffn't from `ptr-to-fn'?
A: A member fn of class X has type: Returntype (X::*)(Argtypes)
while a plain function has type: Returntype (*) (Argtypes)
==============================================================================
Q113: How can I ensure `X's objects are only created with new, not on the stack?
A: Make constructors protected and define `friend' or `static' fns that return
a ptr to objects created via `new' (the ctors must be protected rather than
private, otherwise you couldn't derive from the class). Ex:

class X { //only want to allow dynamicly allocated X's
protected:
X();
X(int i);
X(const X& x);
virtual ~X();
public:
static X* create() { return new X(); }
static X* create(int i) { return new X(i); }
static X* create(const X& x) { return new X(x); }
};

X* Xptr = X::create(5);
==============================================================================
Q114: How do I pass a ptr to member fn to a signal handler,X event callback,etc?
A: Because a member function is meaningless without an object to invoke it on,
you can't do this directly (if `X' were rewritten in C++, it would probably
pass references to *objects* around, not just pointers to fns; naturally the
objects would embody the required function and probably a whole lot more).

As a patch for existing software, use a free function as a wrapper which takes
an object obtained through some other technique (held in a global, perhaps) and
calls the desired member function. There is one exception: static member
functions do not require an actual object to be invoked, and ptrs-to-static-
member-fns are type compatible with regular ptrs-to-fns (see ARM p.25, 158).

Ex: suppose you want to call X::memfn() on interrupt:

class X {
public:
void memfn();
static void staticmemfn(); //a static member fn can handle it
//...
};

//wrapper fn remembers the object on which to invoke memfn in a static var:
static X* object_which_will_handle_signal;
void X_memfn_wrapper() { object_which_will_handle_signal.memfn(); }

main()
{
/* signal(SIGINT, X::memfn); */ //Can NOT do this
signal(SIGINT, X_memfn_wrapper); //Ok
signal(SIGINT, X::staticmemfn); //Also Ok
}
==============================================================================
Q115: Why am I having trouble taking the address of a C++ function?
Short ans: Please read previous question first; this is a corollary.

Long ans: In C++, member fns have an implicit parameter which points to the
object (the `this' ptr inside the member fn). Normal C fns can be thought of
as having a different calling convention from member fns, so the types of their
ptrs (ptr-to-member-fn vs ptr-to-fn) are different and incompatible. C++
introduces a new type of ptr, called a ptr-to-member, which can only be invoked
by providing an object (see ARM 5.5). Do NOT attempt to `cast' a ptr-to-mem-fn
into a ptr-to-fn; the result is undefined and probably disastrous; a ptr-to-
member-fn is NOT required to contain the machine addr of the appropriate fn
(see ARM, 8.1.2c, p.158). As was said in the last example, if you want a
regular C fn ptr, use either a top-level (non-class) fn, or a `static' (class)
member fn.
==============================================================================
Q116: How do I declare an array of pointers to member functions?
A: Use the following declaration:

class Frob {
public:
Rettype f(T1 x, T2 y);
Rettype g(T1 x, T2 y);
Rettype h(T1 x, T2 y);
Rettype i(T1 x, T2 y);
//...
};

Rettype (Frob::*fn_ptr[3])(T1,T2) = { &Frob::f, &Frob::g, &Frob::h };

You can make the array declaration somewhat clearer with a typedef:
typedef Rettype (Frob::*Frob_member_ptr)(T1,T2);
//...
Frob_member_ptr fn_ptr[3] = { &Frob::f, &Frob::g, &Frob::h };

To call one of the functions on an object `frob', use:
Frob frob;
//...
(frob.*fn_ptr[i])(x, y);

You can make the call somewhat clearer using a #define:
#define apply_member_fn(object,fn) ((object).*(fn))
//...
apply_member_fn(frob,fn_ptr[i])(x, y)
==============================================================================
==============================================================================
Q117: How can I insert/access/change elements from a linked list/hashtable/etc?
A: I'll use a `inserting into a linked list' as a prototypical example. The
obvious approach is to allow insertion at the head and tail of the list, but
that would produce a library that is too weak (a weak library is almost worse
than no library). Whenever encapsulation frustrates rather than helps a user,
it may be that the class' public interface needs enhancing. If class List only
supports adding at the front and tail, it *definitely* needs more strength.

This answer will be a lot to swallow for novice C++'ers, so I'll give a couple
of options. As usual, the first is easiest, while the second option is better.
I also give a thumbnail sketch of a third option, which has certain advantages
and disadvantages over the second option.

[1] Empower the List with a `viewport' or `cursor' that references an arbitrary
list element. Implies adding member fns to List such as advance(), backup(),
atend(), atbegin(), rewind(), fastforward(), and current(). `current()'
returns the element of the List that is currently `under the cursor'. Finally
you'll need to add a few more member fns to *mutate* the list, such as
changeto(X), insert(X), remove(), etc.

[2] Provide a separate class called ListIter. ListIter has member fns named
similar to the above (though probably with operator overloading, but that's
just syntactic sugar for member fns). The List itself would have none of the
above mentioned member fns, and the ListIter would be a `friend' of List
(ListIter would have to have access to the innards of List; this allows the
world to have safe access abilities to List without violating encapsulation).

The reason option [2] is better becomes apparent when you use classes that only
support [1]. In particular, if you pass a List off to a subcall, you'd better
hope the subcall didn't warp the `cursor' around, or your code may fail. Also,
if you try to get all pairs of elements, it's very hard if you only have one
cursor. The distinct-class iterator concept removes these restrictions. My
own class library uses these extensively, as will most any other commercial
grade class library.

Note that the options are not mutually exclusive; it is possible to provide
both [2] *and* [1], giving rise to the notion of a `primary' list position,
with instances of ListIter being somewhat secondary.

[3] The third possibility considers the entire iteration as an atomic event. A
class is created which embodies this event. The nice thing about this third
alternative is that the public access methods (which may be virtual fns) can be
avoided during the inner loop, thus enhancing performance. The down side is
that you get extra object code in the application, since templates gain speed
by duplicating code. This third technique is due to Andrew Koenig in a paper
published recently in JOOP [`Templates as interfaces', JOOP, 4, 5 (Sept 91)].
You can also see a taste of it in Bjarne Stroustrup's book, The C++ Programming
Language Second Edition (look for `Comparator' in the index).
==============================================================================
Q118: What's the idea behind `templates'?
A: 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 classes that all
look basically the same, and a function template describes how to build similar
looking functions.

The questions about templates are in the `Containers' section since templates
are often used to build type safe containers (although this only scratches the
surface for how they can be used). We will see how to use templates to build
container classes below.
==============================================================================
Q119: What's the syntax / semantics for a `function template'?
A: 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. Ex:

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').
==============================================================================
Q120: What's the syntax / semantics for a `class template'?
A: Consider this container class of that acts like an array of integers:

//this would go into a header file such as `Vec.h':
class Vec {
int xlen;
int* xdata;
int check(int i); //return i if i>=0 && i public:
int len() const { return xlen; }
const int& operator[](int i) const { xdata[check(i)]; }
int& operator[](int i) { xdata[check(i)]; }
Vec(int L=10) : xlen(L), xdata(new int[L]) { /*verify*/ }
~Vec() { delete [] xdata; }
};

//this would be part of a `.C' file such as `Vec.C':
int Vec::check(int i)
{
if (i <>= xlen) throw BoundsViol("Vec", i, xlen);
return i;
}

Just as with `swap()' above, repeating the above over and over for Vec of
float, char, String, Vec, Vec-of-Vec-of-Vec, etc, will become tedious. Hence
we create a single class template:

//this would go into a header file such as `Vec.h':
template
class Vec {
int xlen;
T* xdata;
int check(int i); //return i if i>=0 && i public:
int len() const { return xlen; }
const T& operator[](int i) const { xdata[check(i)]; }
T& operator[](int i) { xdata[check(i)]; }
Vec(int L=10) : xlen(L), xdata(new T[L]) { /*verify*/ }
~Vec() { delete [] xdata; }
};

//this would be part of a `.C' file such as `Vec.C':
template
int Vec::check(int i)
{
if (i <>= xlen) throw BoundsViol("Vec", i, xlen);
return i;
}

Unlike template functions, template classes (instantiations of class templates)
need to be explicit about the parameters over which they are instantiating:

main()
{
Vec vi;
Vec vf;
Vec vc;
Vec vs;
Vec<> vv;
} // ^^^-- note the space; do NOT use Vec> since the
// `maximal munch' rule would grab a single `>>' token
==============================================================================
Q121: What is a `parameterized type'?
A: A parameterized type is a type that is parameterized over another value or
type. Ex: List is a type that is parameterized over another type, `int'.
Therefore the C++ rendition of parameterized types is provided by class
templates.
==============================================================================
Q122: What is `genericity'?
A: Not to be confused with `generality' (which just means avoiding solutions
which are overly specific), `genericity' means parameterized types. In C++,
this is provided by class templates.
==============================================================================
Q123: How can I fake templates if I don't have a compiler that supports them?
A: The best answer is: buy a compiler that supports templates. When this is
not feasible, the next best answer is to buy or build a template preprocessor
(ex: reads C++-with-templates, outputs C++-with-expanded-template-classes; such
a system needn't be perfect; it cost my company about three man-weeks to
develop such a preprocessor). If neither of these is feasible, you can use the
macro preprocessor to fake templates. But beware: it's tedious; templates are
a better solution wrt development and maintenance costs.

Here's how you'd declare my `Vec' example from above. First we define `Vec(T)'
to concatenate the name `Vec' with that of the type T (ex: Vec(String) becomes
`VecString'). This would go into a header file such as Vec.h:

#include //to get the `name2()' macro
#define Vec(T) name2(Vec,T)

Next we declare the class Vec(T) using the name `Vecdeclare(T)' (in general you
would postfix the name of the class with `declare', such as `Listdeclare' etc):

#define Vecdeclare(T)
\
class Vec(T) {
\
int xlen;
\
T* xdata;
\
int check(int i); /*return i if in bounds else throw*/ \
public:
\
int len() const { return xlen; } \
const T& operator[](int i) const { xdata[check(i)]; } \
T& operator[](int i) { xdata[check(i)]; } \
Vec(T)(int L=10): xlen(L), xdata(new T[L]) {/*...*/}\
~Vec(T)() { delete [] xdata; } \
};

Note how each occurrence of `Vec' has the `(T)' postfixed. Finally we set up
another macro that `implements' the non-inline member function(s) of Vec:

//strangely enough this can also go into Vec.h
#define Vecimplement(T)
\
int Vec(T)::check(int i)
\
{
\
if (i <>= xlen) throw BoundsViol("Vec", i, xlen); \
return i;
\
}

When you wish to use a Vec-of-String and Vec-of-int, you would say:

#include "Vec.h" //pulls in too; see below...
declare(Vec,String) //`declare()' is a macro defined in
declare(Vec,int)
Vec(String) vs; //Vec(String) becomes the single token `VecString'
Vec(int) vi;

In exactly one source file in the system, you must provide implementations for
the non-inlined member functions:

#include "Vec.h"
declare (Vec,String) declare (Vec,int) declare (Vec,float)
implement(Vec,String) implement(Vec,int) implement(Vec,float)

Note that types whose names are other than a single identifier do not work
properly. Ex: Vec(char*) creates a class whose name is `Vecchar*'. The patch
is to create a typedef for the appropriate type:

#include "Vec.h"
typedef char* charP;
declare(Vec,charP)

It is important that every declaration of what amounts to `Vec' must all
use exactly the same typedef, otherwise you will end up with several equivalent
classes, and you'll have unnecessary code duplication. This is the sort of
tedium which a template mechanism can handle for you.
==============================================================================
==============================================================================
Q124: Why don't variable arg lists work for C++ on a Sun SPARCstation?

A: That is a bug in cfront 2.1. There is a magic variable, __builtin_va_alist.
It has to be added to the end of the argument list of a varadic function, and
it has to be referenced in va_start. This requires source modification to (a)
print `,__builtin_va_alist' on the end of the argument list, (b) pretend that
this arg was declared, and thus pass references to it, and © not mangle its
name in the process.

Here's a tiny bit more detail:
1) when print2.c prints a varadic procedure, it should add __builtin_va_alist
to the end. It need not declare it. Type of int to the Sun C compiler (the
default) is fine.
2) #define va_start(ap,parmN) ap = (char *)&__builtin_va_alist
3) when find.c see this reference to __builtin_va_alist, it should construct a
special cfront name node. When name::print sees that node it should print
its name literally, without adding any mangling.
4) the same trick is needed, with the name va_alist, for Ultrix/MIPS and HPUX.
5) the net result, in generated C code, looks like:
void var_proc (a, b, c, __builtin_va_alist)
int a;
float b;
char * c;
{
char * val;
val = &__builtin_va_alist;
...
}
==============================================================================
Q125: GNU C++ (g++) produces big executables for tiny programs; Why?
A: 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 (~1 Meg; 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.
==============================================================================
Q126: Is there a yacc-able C++ grammar?
A: 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. Jim's grammar
deviates from cfront (and the ARM) in a couple of what I understand to be minor
ways. Ultimately any deviation from a standard is unthinkable, but the number
of real programs that are interpreted differently is relatively small, so the
`consequence' of the deviation is not great.

I have used Jim's grammar when a grad student wrote a C++ templatizer mechanism
(reads ANSI-C++, spits out pre-templates C++), but my expertise does not include precise knowledge of where the grammar deviates from `official'. I have found it to parse most things correctly, but I am aware that there are differences. (is that noncommittal enough? :-)

The grammar can be accessed by anonymous ftp from the following sites:
* ics.uci.edu (128.195.1.1) in the ftp/gnu directory (even though neither of the archives are GNU related) as:
c++grammar2.0.tar.Z and byacc1.8.tar.Z
* mach1.npac.syr.edu (128.230.7.14) in the ftp/pub/C++ directory as:
c++grammar2.0.tar.Z and byacc1.8.tar.z

Jim Roskind can be reached at jar@hq.ileaf.com or ...!uunet!leafusa!jar
==============================================================================
Q127: What is C++ 1.2? 2.0? 2.1? 3.0?
A: These are not versions of the language, but rather versions of the USL translator, cfront. However many people discuss these as levels of the language as well, since each of the above versions represents additions to the portion of the C++ language which is implemented by the compiler. When ANSI/ISO C++ is finalized, conformance with the ANSI/ISO spec will become more important than conformance with cfront version X.Y, but presently, cfront is acting as a de facto standard to help coordinate the industry (although it leaves certain features of the language unimplemented as well).

*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 [] ptr_to_array'.
* 3.0 includes fully-nested classes, templates and `i++' vs `++i'.
*?4.0? will include exceptions.
==============================================================================
Q128: How does the lang accepted by cfront 3.0 differ from that accepted by 2.1?
A: USL cfront release 3.0 provides implementations of a number of features that
were previously flagged as `sorry not implemented':
templates, fully nested types, prefix and postfix increment and decrement
operators, initialization of single dimension arrays of class objects with
ctors taking all default arguments, use of operators &&, , and ?: with
expressions requiring temporaries of class objects containing destructors,
and implicit named return values.

The major feature not accepted by cfront 3.0 is exceptions.
==============================================================================
Q129: Why are exceptions going to be implemented after templates? Why not both?
A: Most C++ compiler vendors are providing templates in their present release,
but very few are providing exceptions (I know of only one). The reason for going slowly is that both templates and exception handling are difficult to implement *well*. A poor template implementation will give slow compile and link times and a poor exception handling implementation will give slow run times. Good implementations will not have those problems.

C++ compiler vendors are human beings too, and they can only get so much done
at once. However they know that the C++ community is craving for the `whole'
language, so they'll be pushing hard to fill that need.
==============================================================================
Q130: What was C++ 1.xx, and how is it different from the current C++ language?
A: C++ 1.2 (the version number corresponds to the release number of USL's cfront) corresponds to Bjarne Stroustrup's first edition (`The C++ Programming
Language', ISBN 0-201-12078-X). In contrast, the present version (3.0) corresponds roughly to the `ARM', except for exceptions. Here is a summary of
the differences between the first edition of Bjarne's book and the ARM:
- A class can have more than one direct base class (multiple inheritance).
- Class members can be `protected'.
- Pointers to class members can be declared and used.
- Operators `new' and `delete' can be overloaded and declared for a class.
This allows the "assignment to `this'" technique for class specific
specific storage management to be removed to the anachronism section
- Objects can be explicitly destroyed.
- Assignment and Copy-Initialization default to member-wise assignment and
copy-initialization.
- The `overload' keyword was made redundant and removed to the anachronism
section.
- General expressions are allowed as initializers for static objects.
- Data objects can be `volatile' (new keyword).
- Initializers are allowed for `static' class members.
- Member functions can be `static'.
- Member functions can be `const' or `volatile'.
- Linkage to non-C++ program fragments can be explicitly declared.
- Operators `->', `->*' and `,' can be overloaded.
- Classes can be abstract.
- Prefix and postfix application of `++' and `--' on a user-defined type can be distinguished.
- Templates.
- Exception handling.
==============================================================================
SUBSECTION: Miscellaneous technical issues
==============================================================================
Q131: Why are classes with static data members getting linker errors?
A: Static member variables must be given an explicit definition in exactly one
module. Ex:
class X {
//...
static int i; //*declare* static member X::i
//...
};
The linker will holler at you (`X::i is not defined') unless (exactly) one of
your source files has something like the following:
int X::i = some_expression_evaluating_to_an_int; //*define* X::i
or:
int X::i; //define --but don't initialize-- X::i

The usual place to define static member variables of class `X' is file `X.C'
(or X.cpp, X.cc, X.c++, X.c or X.cxx; see question on file naming conventions).
==============================================================================
Q132: What's the difference between the keywords struct and class?
A: The members and base classes of a struct are public by default, while in
class, they default to private. Base classes of a struct are public by default
while they are private by default with `class' (however you should make your
base classes *explicitly* public, private, or protected). `Struct' and `class'
are otherwise functionally equivalent.
==============================================================================
Q133: Why can't I overload a function by its return type?
Ex: the compiler says the following two are an error:
char f(int i);
float f(int i);

A: Return types are not considered when determining unique signatures for
overloading functions; only the number and type of parameters are considered.
Reason: which function should be called if the return value is ignored? Ex:

main()
{
f(3); //which should be invoked??
}
==============================================================================
Q134: What is `persistence'? What is a `persistent object'?
A: Loosely speaking, a persistent object is one that lives on after the
program which created it has stopped. Persistent objects can even outlive
various 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 method
code out on secondary storage along with their data bits (and the data bits
and method code of all subobjects, and of all their subobjects, 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.
==============================================================================
SUBSECTION: Miscellaneous environmental issues
==============================================================================
Q135: Is there a TeX or LaTeX macro that fixes the spacing on `C++'?
A: Yes, here are two:

\def\CC{C\raise.22ex\hbox{{\footnotesize +}}\raise.22ex\hbox{\footnotesize +}}

\def\CC{{C\hspace{-.05em}\raisebox{.4ex}{\tiny\bf ++}}}
==============================================================================
Q136: Where can I access C++2LaTeX, a LaTeX pretty printer for C++ source?
A: Here are a few ftp locations:

Host aix370.rrz.uni-koeln.de (134.95.80.1) Last updated 15:41 26 Apr 1991
Location: /tex
FILE rw-rw-r-- 59855 May 5 1990 C++2LaTeX-1.1.tar.Z
Host utsun.s.u-tokyo.ac.jp (133.11.11.11) Last updated 05:06 20 Apr 1991
Location: /TeX/macros
FILE rw-r--r-- 59855 Mar 4 08:16 C++2LaTeX-1.1.tar.Z
Host nuri.inria.fr (128.93.1.26) Last updated 05:23 9 Apr 1991
Location: /TeX/tools
FILE rw-rw-r-- 59855 Oct 23 16:05 C++2LaTeX-1.1.tar.Z
Host iamsun.unibe.ch (130.92.64.10) Last updated 05:06 4 Apr 1991
Location: /TeX
FILE rw-r--r-- 59855 Apr 25 1990 C++2LaTeX-1.1.tar.Z
Host iamsun.unibe.ch (130.92.64.10) Last updated 05:06 4 Apr 1991
Location: /TeX
FILE rw-r--r-- 51737 Apr 30 1990
C++2LaTeX-1.1-PL1.tar.Z
Host tupac-amaru.informatik.rwth-aachen.de (192.35.229.9) Last updated 05:07 18 Apr 1991
Location: /pub/textproc/TeX
FILE rw-r--r-- 72957 Oct 25 13:51 C++2LaTeX-1.1-PL4.tar.Z
Host wuarchive.wustl.edu (128.252.135.4) Last updated 23:25 30 Apr 1991
Location: /packages/tex/tex/192.35.229.9/textproc/TeX
FILE rw-rw-r-- 49104 Apr 10 1990 C++2LaTeX-PL2.tar.Z
FILE rw-rw-r-- 25835 Apr 10 1990 C++2LaTeX.tar.Z
Host tupac-amaru.informatik.rwth-aachen.de (192.35.229.9) Last updated 05:07 18 Apr 1991
Location: /pub/textproc/TeX
FILE rw-r--r-- 74015 Mar 22 16:23 C++2LaTeX-1.1-PL5.tar.Z
Location: /pub
FILE rw-r--r-- 74015 Mar 22 16:23 C++2LaTeX-1.1-PL5.tar.Z
Host sol.cs.ruu.nl (131.211.80.5) Last updated 05:10 15 Apr 1991
Location: /TEX/TOOLS
FILE rw-r--r-- 74015 Apr 4 21:02x C++2LaTeX-1.1-PL5.tar.Z
Host tupac-amaru.informatik.rwth-aachen.de (192.35.229.9) Last updated 05:07 18 Apr 1991
Location: /pub/textproc/TeX
FILE rw-r--r-- 4792 Sep 11 1990 C++2LaTeX-1.1-patch#1
FILE rw-r--r-- 2385 Sep 11 1990 C++2LaTeX-1.1-patch#2
FILE rw-r--r-- 5069 Sep 11 1990 C++2LaTeX-1.1-patch#3
FILE rw-r--r-- 1587 Oct 25 13:58 C++2LaTeX-1.1-patch#4
FILE rw-r--r-- 8869 Mar 22 16:23 C++2LaTeX-1.1-patch#5
FILE rw-r--r-- 1869 Mar 22 16:23 C++2LaTeX.README
Host rusmv1.rus.uni-stuttgart.de (129.69.1.12) Last updated 05:13 13 Apr 1991
Location: /soft/tex/utilities
FILE rw-rw-r-- 163840 Jul 16 1990 C++2LaTeX-1.1.tar
==============================================================================
Q137: Where can I access `tgrind', a pretty printer for C++/C/etc source?
A: `tgrind' reads the file to be printed and a command line switch to see what
the source language is. It then reads a language definition database file and
learns the syntax of the language (list of keywords, literal string delimiters,
comment delimiters, etc).

`tgrind' 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:
venus.ycc.yale.edu in [.TGRIND]
==============================================================================
Q138: Is there a C++-mode for GNU emacs? If so, where can I get it?
A: Yes, there is a C++-mode for GNU emacs. You can get it via:

c++-mode-2 (1.0) 87-12-08
Bruce Eckel,Thomas Keffer, beaver!beluga!eckel,keffer@sperm.ocean.washington.edu>
archive.cis.ohio-state.edu:/pub/gnu/emacs/elisp-archive/as-is/c++-mode-2.el.Z

Another C++ major mode.
c++-mode 89-11-07
Dave Detlefs, et al,
archive.cis.ohio-state.edu:/pub/gnu/emacs/elisp-archive/modes/c++-mode.el.Z

C++ major mode.
c++ 90-02-01
David Detlefs, Stewart Clamen,
archive.cis.ohio-state.edu:/pub/gnu/emacs/elisp-archive/modes/c++.el.Z
C++ code editing commands for Emacs

c-support (46) 89-11-04
Lynn Slater,
archive.cis.ohio-state.edu:/pub/gnu/emacs/elisp-archive/misc/c-support.el.Z
Partial support for team C/C++ development.
==============================================================================
Q139: What is `InterViews'?
A: A non-proprietary toolkit for graphic user interface programming in C++,
developed by Mark Linton and others when he was at Stanford. Unlike C++
wrappers for C libraries such as Motif, InterViews is a true object library.
Commercially maintained versions are available from Quest, while freely
redistributable versions (running on top of X) from interviews.stanford.edu (an
ftp site). Copies of this are (were?) distributed with the regular X
distribution. Other sources of information include comp.windows.interviews,
which has its own FAQ.
==============================================================================
Q140: Where can I get OS-specific questions answered (ex:BC++,DOS,Windows,etc)?
A: see comp.os.msdos.programmer, BC++ and Zortech mailing lists, BC++ and
Zortech bug lists, comp.windows.ms.programmer, comp.unix.programmer, etc.

You can subscribe to the BC++ mailing list by sending email to:
To: listserv@ucf1vm.cc.ucf.edu <---or LISTSERV@UCF1VM.BITNET
Subject: SUB TCPLUS-L
Reply-to: you@your.email.addr <---ie: put your return address here

The BC++ bug report is available via anonymous ftp from sun.soe.clarkson.edu
[128.153.12.3] from the file ~ftp/pub/Turbo-C++/bug-report
(also, I post it on comp.lang.c++ on the first each month).

Relevant email addresses:
ztc-list@zortech.com General requests and discussion
ztc-list-request@zortech.com Requests to be added to ztc-list
ztc-bugs@zortech.com For _short_ bug reports
==============================================================================
Q141: Why does my DOS C++ program says `Sorry: floating point code not linked'?
A: The compiler attempts to save space in the executable by not including the
float-to-string format conversion routines unless they are necessary, and
sometimes does not recognize some code that does require it. Taking the address
of a float in an argument list of a function call seems to trigger it, but
taking the address of a float element of a struct may fool the compiler. A
"%f" in a printf/scanf format string doesn't trigger it because format strings
aren't examined at compile-time.

You can fix it by (1) using instead of , or (2) by
including the following function definition somewhere in your compilation (but
don't call it!):
static void dummyfloat(float *x) { float y; dummyfloat(&y); }

See question on stream I/O for more reasons to use vs .
==============================================================================

No comments: