[6.1] Is C++ a practical language?
Yes.
C++ is a practical tool. It's not perfect[6.2], but it's useful.
In the world of industrial software, C++ is viewed as a solid, mature,
mainstream tool. It has widespread industry support which makes it "good" from
an overall business perspective.
==============================================================================
[6.2] Is C++ a perfect language?
Nope.
C++ wasn't designed to demonstrate what a perfect OO language looks like. It
was designed to be a practical tool for solving real world problems. It has a
few warts, but the only place where it's appropriate to keep fiddling with
something until it's perfect is in a pure academic setting. That wasn't C++'s
goal.
==============================================================================
[6.3] What's the big deal with OO?
Object-oriented techniques are the best way we know of to develop large,
complex software applications and systems.
OO hype: the software industry is "failing" to meet demands for large, complex
software systems. But this "failure" is actually due to our successes: our
successes have propelled users to ask for more. Unfortunately we created a
market hunger that the "structured" analysis, design and programming techniques
couldn't satisfy. This required us to create a better paradigm.
C++ is an OO programming language. C++ can also be used as a traditional
programming language (as "as a better C"). However if you use it "as a better
C," don't expect to get the benefits of object-oriented programming.
==============================================================================
[6.4] Is C++ better than Ada? (or Visual Basic, C, FORTRAN, Pascal, Smalltalk,
or any other language?)
This question generates much much more heat than light. Please read the
following before posting some variant of this question.
In 99% of the cases, programming language selection is dominated by business
considerations, not by technical considerations. Things that really end up
mattering are things like availability of a programming environment for the
development machine, availability of runtime environment(s) for the deployment
machine(s), licensing/legal issues of the runtime and/or development
environments, availability of trained developers, availability of consulting
services, and corporate culture/politics. These business considerations
generally play a much greater role than compile time performance, runtime
performance, static vs. dynamic typing, static vs. dynamic binding, etc.
Anyone who argues in favor of one language over another in a purely technical
manner (i.e., who ignores the dominant business issues) exposes themself as a
techie weenie, and deserves not to be heard.
==============================================================================
[6.5] Who uses C++?
Lots and lots of companies and government sites. Lots.
The number of C++ developers increases 20-30% every year. You can imagine that
five people are becoming C++ developers while you read this FAQ.
Growth is one of several critical features of C++[6.7].
[6.8] Are virtual functions (dynamic binding) central to OO/C++? [UPDATED!]
[Recently reworded the second paragraph thanks to Stan Brown (on 1/00).]
Yes!
Without virtual functions[20], C++ wouldn't be object-oriented. Operator
overloading[13] and non-virtual member functions are great, but they are, after
all, just syntactic sugar for the more typical C notion of passing a pointer to
a struct to a function. STL and other "generic programming" techniques are
great too, but virtual functions are still at the heart of object-oriented
programming using C++.
From a business perspective, there is very little reason to switch from
straight C to C++ without virtual functions (we'll ignore generic programming
and STL in this FAQ). Technical people often think that there is a large
difference between C and non-OO C++, but without OO, difference usually isn't
enough to justify the cost of training developers, new tools, etc. In other
words, if I were to advise a manager regarding whether to switch from C to
non-OO C++ (i.e., to switch languages but not paradigms), I'd probably
discourage him or her unless there were compelling tool-oriented reasons. From
a business perspective, OO can help make systems extensible andadaptable, but
just the syntax of C++ classes without OO may not even reduce the maintenance
cost, and it surely adds to the training cost significantly.
Bottom line: C++ without virtual is not OO. Programming with classes but
without dynamic binding is called "object based," but not "object oriented."
Throwing out virtual functions is the same as throwing out OO. All you have
left is object-based programming, similar to the original Ada language (the new
Ada language, by the way, supports true OO rather than just object-based
programming).
==============================================================================
[6.9] I'm from Missouri. Can you give me a simple reason why virtual functions
(dynamic binding) make a big difference?
Overview: Dynamic binding can improve reuse by letting old code call new code.
Before OO came along, reuse was accomplished by having new code call old code.
For example, a programmer might write some code that called some reusable code
such as printf().
With OO, reuse can also be accomplished by having old code call new code. For
example, a programmer might write some code that is called by a framework that
was written by their great, great grandfather. There's no need to change
great-great-grandpa's code. In fact, it doesn't even need to be recompiled.
Even if all you have left is the object file and the source code that
great-great-grandpa wrote was lost 25 years ago, that ancient object file will
call the new extension without anything falling apart.
That is extensibility, and that is OO.
==============================================================================
[6.10] Is C++ backward compatible with ANSI/ISO-C?
Almost.
C++ is as close as possible to compatible with C, but no closer. In practice,
the major difference is that C++ requires prototypes, and that f() declares a
function that takes no parameters (in C, f() is the same as f(...)).
There are some very subtle differences as well, like sizeof('x') is equal to
sizeof(char) in C++ but is equal to sizeof(int) in C. Also, C++ puts structure
"tags" in the same namespace as other names, whereas C requires an explicit
struct (e.g., the typedef struct Fred Fred; technique still works, but is
redundant in C++).
==============================================================================
[6.11] Is C++ standardized? [UPDATED!]
[Recently changed "American National Standards Organization" to "American
National Standards Institute" thanks to Mark Jones; also reworded first
paragraph thanks to Stan Brown (on 1/00).]
Yes.
The C++ standard was finalized and adopted by ISO (International Organization
for Standardization) as well as several national standards organizations such
as ANSI (The American National Standards Institute), BSI (The British Standards
Institute), DIN (The German National Standards Organization). The ISO standard
has been finalized and adopted by unanimous vote November 14, 1997.
The ANSI-C++ committee is called "X3J16". The ISO C++ standards group is
called "WG21". The major players in the ANSI/ISO C++ standards process
includes just about everyone: representatives from Australia, Canada, Denmark,
France, Germany, Ireland, Japan, the Netherlands, New Zealand, Sweden, the UK,
and the USA, along with representatives from about a hundred companies and many
interested individuals. Major players include AT&T, Ericsson, Digital,
Borland, Hewlett Packard, IBM, Mentor Graphics, Microsoft, Silicon Graphics,
Sun Microsystems, and Siemens. After about 8 years of work, this standard is
now complete. On November 14, 1997, the standard was approved by a unanimous
vote of the countries that had representatives present in Morristown.
[7.1] What is a class?
The fundamental building block of OO software.
A class defines a data type, much like a struct would be in C. In a computer
science sense, a type consists of both a set of states and a set of operations
which transition between those states. Thus int is a type because it has both
a set of states and it has operations like i + j or i++, etc. In exactly the
same way, a class provides a set of (usually public:) operations, and a set of
(usually non-public:) data bits representing the abstract values that instances
of the type can have.
You can imagine that int is a class that has member functions called
operator++, etc. (int isn't really a class, but the basic analogy is this: a
class is a type, much like int is a type.)
Note: a C programmer can think of a class as a C struct whose members default
to private. But if that's all you think of a class, then you probably need to
experience a personal paradigm shift.
==============================================================================
[7.2] What is an object?
A region of storage with associated semantics.
After the declaration int i; we say that "i is an object of type int." In
OO/C++, "object" usually means "an instance of a class." Thus a class defines
the behavior of possibly many objects (instances).
==============================================================================
[7.3] When is an interface "good"?
When it provides a simplified view of a chunk of software, and it is expressed
in the vocabulary of a user (where a "chunk" is normally a class or a tight
group of classes[14.2], and a "user" is another developer rather than the
ultimate customer).
* The "simplified view" means unnecessary details are intentionally hidden.
This reduces the user's defect-rate.
* The "vocabulary of users" means users don't need to learn a new set of words
and concepts. This reduces the user's learning curve.
==============================================================================
[7.4] What is encapsulation?
Preventing unauthorized access to some piece of information or functionality.
The key money-saving insight is to separate the volatile part of some chunk of
software from the stable part. Encapsulation puts a firewall around the chunk,
which prevents other chunks from accessing the volatile parts; other chunks can
only access the stable parts. This prevents the other chunks from breaking if
(when!) the volatile parts are changed. In context of OO software, a "chunk"
is normally a class or a tight group of classes[14.2].
The "volatile parts" are the implementation details. If the chunk is a single
class, the volatile part is normally encapsulated using the private: and/or
protected: keywords[19.5]. If the chunk is a tight group of classes[14.2],
encapsulation can be used to deny access to entire classes in that group.
Inheritance[19] can also be used as a form of encapsulation[22.2].
The "stable parts" are the interfaces. A good interface provides a simplified
view in the vocabulary of a user[7.3], and is designed from the
outside-in[13.10] (here a "user" means another developer, not the end-user who
buys the completed application). If the chunk is a single class, the interface
is simply the class's public: member functions and friend[14] functions. If
the chunk is a tight group of classes[14.2], the interface can include several
of the classes in the chunk.
Designing a clean interface and separating that interface from its
implementation[22.1] merely allows users to use the interface. But
encapsulating (putting "in a capsule") the implementation forces users to use
the interface.
==============================================================================
[7.5] How does C++ help with the tradeoff of safety vs. usability?
In C, encapsulation[7.4] was accomplished by making things static in a
compilation unit or module. This prevented another module from accessing the
static stuff. (By the way, that use is now deprecated: don't do that in C++.)
Unfortunately this approach doesn't support multiple instances of the data,
since there is no direct support for making multiple instances of a module's
static data. If multiple instances were needed in C, programmers typically
used a struct. But unfortunately C structs don't support encapsulation[7.4].
This exacerbates the tradeoff between safety (information hiding) and usability
(multiple instances).
In C++, you can have both multiple instances and encapsulation via a class.
The public: part of a class contains the class's interface, which normally
consists of the class's public: member functions and its friend[14] functions.
The private: and/or protected:[19.5] parts of a class contain the class's
implementation, which is typically where the data lives.
The end result is like an "encapsulated struct." This reduces the tradeoff
between safety (information hiding) and usability (multiple instances).
==============================================================================
[7.6] How can I prevent other programmers from violating encapsulation by
seeing the private parts of my class?
Not worth the effort -- encapsulation is for code, not people.
It doesn't violate encapsulation for a programmer to see the private: and/or
protected:[19.5] parts of your class, so long as they don't write code that
somehow depends on what they saw. In other words, encapsulation doesn't
prevent people from knowing about the inside of a class; it prevents the code
they write from becoming dependent on the insides of the class. Your company
doesn't have to pay a "maintenance cost" to maintain the gray matter between
your ears; but it does have to pay a maintenance cost to maintain the code that
comes out of your finger tips. What you know as a person doesn't increase
maintenance cost, provided the code they write depends on the interface rather
than the implementation.
Besides, this is rarely if ever a problem. I don't know any programmers who
have intentionally tried to access the private parts of a class. "My
recommendation in such cases would be to change the programmer, not the code"
[James Kanze; used with permission].
==============================================================================
[7.7] Is Encapsulation a Security device?
No.
Encapsulation != security.
Encapsulation prevents mistakes, not espionage.
==============================================================================
[7.8] What's the difference between the keywords struct and class?
The members and base classes of a struct are public by default, while in class,
they default to private. Note: you should make your base classes explicitly
public, private, or protected, rather than relying on the defaults.
struct and class are otherwise functionally equivalent.
OK, enough of that squeaky clean techno talk. Emotionally, most developers
make a strong distinction between a class and a struct. A struct simply feels
like an open pile of bits with very little in the way of encapsulation or
functionality. A class feels like a living and responsible member of society
with intelligent services, a strong encapsulation barrier, and a well defined
interface. Since that's the connotation most people already have, you should
probably use the struct keyword if you have a class that has very few methods
and has public data (such things do exist in well designed systems!), but
otherwise you should probably use the class keyword.
==============================================================================
SECTION [8]: References
[8.1] What is a reference?
An alias (an alternate name) for an object.
References are frequently used for pass-by-reference:
void swap(int& i, int& j)
{
int tmp = i;
i = j;
j = tmp;
}
int main()
{
int x, y;
// ...
swap(x,y);
}
Here i and j are aliases for main's x and y respectively. In other words, i is
x -- not a pointer to x, nor a copy of x, but x itself. Anything you do to i
gets done to x, and vice versa.
OK. That's how you should think of references as a programmer. Now, at the
risk of confusing you by giving you a different perspective, here's how
references are implemented. Underneath it all, a reference i to object x is
typically the machine address of the object x. But when the programmer says
i++, the compiler generates code that increments x. In particular, the address
bits that the compiler uses to find x are not changed. A C programmer will
think of this as if you used the C style pass-by-pointer, with the syntactic
variant of (1) moving the & from the caller into the callee, and (2)
eliminating the *s. In other words, a C programmer will think of i as a macro
for (*p), where p is a pointer to x (e.g., the compiler automatically
dereferences the underlying pointer; i++ is changed to (*p)++; i = 7 is
automatically changed to *p = 7).
Important note: Even though a reference is often implemented using an address
in the underlying assembly language, please do not think of a reference as a
funny looking pointer to an object. A reference is the object. It is not a
pointer to the object, nor a copy of the object. It is the object.
==============================================================================
[8.2] What happens if you assign to a reference?
You change the state of the referent (the referent is the object to which the
reference refers).
Remember: the reference is the referent, so changing the reference changes the
state of the referent. In compiler writer lingo, a reference is an "lvalue"
(something that can appear on the left hand side of an assignment operator).
==============================================================================
[8.3] What happens if you return a reference?
The function call can appear on the left hand side of an assignment operator.
This ability may seem strange at first. For example, no one thinks the
expression f() = 7 makes sense. Yet, if a is an object of class Array, most
people think that a[i] = 7 makes sense even though a[i] is really just a
function call in disguise (it calls Array::operator[](int), which is the
subscript operator for class Array).
class Array {
public:
int size() const;
float& operator[] (int index);
// ...
};
int main()
{
Array a;
for (int i = 0; i < a.size(); ++i)
a[i] = 7; // This line invokes Array::operator[](int)
}
==============================================================================
[8.4] How can you reseat a reference to make it refer to a different object?
No way.
You can't separate the reference from the referent.
Unlike a pointer, once a reference is bound to an object, it can not be
"reseated" to another object. The reference itself isn't an object (it has no
identity; taking the address of a reference gives you the address of the
referent; remember: the reference is its referent).
In that sense, a reference is similar to a const pointer[18.5] such as
int* const p (as opposed to a pointer to const[18.4] such as const int* p). In
spite of the gross similarity, please don't confuse references with pointers;
they're not at all the same.
==============================================================================
[8.5] When should I use references, and when should I use pointers?
Use references when you can, and pointers when you have to.
References are usually preferred over pointers whenever you don't need
"reseating"[8.4]. This usually means that references are most useful in a
class's public interface. References typically appear on the skin of an
object, and pointers on the inside.
The exception to the above is where a function's parameter or return value
needs a "sentinel" reference. This is usually best done by returning/taking a
pointer, and giving the NULL pointer this special significance (references
should always alias objects, not a dereferenced NULL pointer).
Note: Old line C programmers sometimes don't like references since they provide
reference semantics that isn't explicit in the caller's code. After some C++
experience, however, one quickly realizes this is a form of information hiding,
which is an asset rather than a liability. E.g., programmers should write code
in the language of the problem rather than the language of the machine.
==============================================================================
SECTION [9]: Inline functions
[9.1] What's the deal with inline functions?
An inline function is a function whose code gets inserted into the caller's
code stream. Like a #define macro, inline functions improve performance by
avoiding the overhead of the call itself and (especially!) by the compiler
being able to optimize through the call ("procedural integration").
==============================================================================
[9.2] How can inline functions help with the tradeoff of safety vs. speed?
In straight C, you can achieve "encapsulated structs" by putting a void* in a
struct, in which case the void* points to the real data that is unknown to
users of the struct. Therefore users of the struct don't know how to interpret
the stuff pointed to by the void*, but the access functions cast the void* to
the approprate hidden type. This gives a form of encapsulation.
Unfortunately it forfeits type safety, and also imposes a function call to
access even trivial fields of the struct (if you allowed direct access to the
struct's fields, anyone and everyone would be able to get direct access since
they would of necessity know how to interpret the stuff pointed to by the
void*; this would make it difficult to change the underlying data structure).
Function call overhead is small, but can add up. C++ classes allow function
calls to be expanded inline. This lets you have the safety of encapsulation
along with the speed of direct access. Furthermore the parameter types of
these inline functions are checked by the compiler, an improvement over C's
#define macros.
==============================================================================
[9.3] Why should I use inline functions? Why not just use plain old #define
macros? [UPDATED!]
[Recently added cross references to other evilness of macros (on 3/00).]
Because #define macros are evil[9.3], evil[34.1], evil[34.2], evil[34.3].
Unlike #define macros, inline functions avoid infamous macro errors since
inline functions always evaluate every argument exactly once. In other words,
invoking an inline function is semantically just like invoking a regular
function, only faster:
// A macro that returns the absolute value of i
#define unsafe(i) \
( (i) >= 0 ? (i) : -(i) )
// An inline function that returns the absolute value of i
inline
int safe(int i)
{
return i >= 0 ? i : -i;
}
int f();
void userCode(int x)
{
int ans;
ans = unsafe(x++); // Error! x is incremented twice
ans = unsafe(f()); // Danger! f() is called twice
ans = safe(x++); // Correct! x is incremented once
ans = safe(f()); // Correct! f() is called once
}
Also unlike macros, argument types are checked, and necessary conversions are
performed correctly.
Macros are bad for your health; don't use them unless you have to.
==============================================================================
[9.4] How do you tell the compiler to make a non-member function inline?
When you declare an inline function, it looks just like a normal function:
void f(int i, char c);
But when you define an inline function, you prepend the function's definition
with the keyword inline, and you put the definition into a header file:
inline
void f(int i, char c)
{
// ...
}
Note: It's imperative that the function's definition (the part between the
{...}) be placed in a header file, unless the function is used only in a single
.cpp file. In particular, if you put the inline function's definition into a
.cpp file and you call it from some other .cpp file, you'll get an "unresolved
external" error from the linker.
==============================================================================
[9.5] How do you tell the compiler to make a member function inline?
When you declare an inline member function, it looks just like a normal member
function:
class Fred {
public:
void f(int i, char c);
};
But when you define an inline member function, you prepend the member
function's definition with the keyword inline, and you put the definition into
a header file:
inline
void Fred::f(int i, char c)
{
// ...
}
It's usually imperative that the function's definition (the part between the
{...}) be placed in a header file. If you put the inline function's definition
into a .cpp file, and if it is called from some other .cpp file, you'll get an
"unresolved external" error from the linker.
==============================================================================
[9.6] Is there another way to tell the compiler to make a member function
inline?
Yep: define the member function in the class body itself:
class Fred {
public:
void f(int i, char c)
{
// ...
}
};
Although this is easier on the person who writes the class, it's harder on all
the readers since it mixes "what" a class does with "how" it does them.
Because of this mixture, we normally prefer to define member functions outside
the class body with the inline keyword[9.5]. The insight that makes sense of
this: in a reuse-oriented world, there will usually be many people who use your
class, but there is only one person who builds it (yourself); therefore you
should do things that favor the many rather than the few.
==============================================================================