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!)
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.
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.
________________________________________
________________________________________
What is encapsulation?
________________________________________
The wrapping of data and functions ito a single unit(called class) is known as encapsulation.
The data is not accessible to the outside world and only those functions which are wrapped in the class can access it. These functions provide the interface between the objects data and the program. This insulation of the data from direct access by the program is called data hiding.
Containing and hiding information about an object, such as internal data structures and code.
Encapsulation isolates the internal complexity of an object's operation from the rest of the application.
For example, a client component asking for net revenue from a business object need not know the data's origin.
________________________________________
What is Polymorphism?
________________________________________
Polymorphism allows a client to treat different objects in the same way even
if they were created from different classes and exhibit different behaviors.
You can use implementation inheritance to achieve polymorphism in languages such as C++ and Java.
Base class object's pointer can invoke methods in derived class objects.
You can also achieve polymorphism in C++ by function overloading and operator overloading.
________________________________________
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
________________________________________
what is the size of class which has int, double, and char?
________________________________________
There are many factors that decide the size of an object of a class in C++. These factors are:
1. Size of all non-static data members
2. Order of data members
3. Byte alignment or byte padding
4. Size of its immediate base class
5. The existence of virtual function(s) (Dynamic polymorphism using virtual functions).
Compiler being used
6. Mode of inheritance (virtual inheritance)
Size of all non-static data members
Only non-static data members will be counted for calculating sizeof class/object.
class A {
private:
float iMem1;
const int iMem2;
static int iMem3;
char iMem4;
};
For an object of class A, the size will be the size of float iMem1 + size of int iMem2 + size of char iMem3. Static members are really not part of the class object. They won't be included in object's layout. <2>Order of data members
The order in which one specifies data members also alters the size of the class.
class C {
char c;
int int1;
int int2;
int i;
long l;
short s;
};
The size of this class is 24 bytes. Even though char c will consume only 1 byte, 4 bytes will be allocated for it, and the remaining 3 bytes will be wasted (holes). This is because the next member is an int, which takes 4 bytes. If we don't go to the next (4th) byte for storing this integer member, the memory access/modify cycle for this integer will be 2 read cycles. So the compiler will do this for us, unless we specify some byte padding/packing.
If I re-write the above class in different order, keeping all my data members like below:
class C {
int int1;
int int2;
int i;
long l;
short s;
char c;
};
Now the size of this class is 20 bytes.
In this case, it is storing c, the char, in one of the slots in the hole in the extra four bytes.
Byte alignment or byte padding
As mentioned above, if we specify 1 byte alignment, the size of the class above (class C) will be 19 in both cases.
Size of its immediate base class
The size of a class also includes size of its immediate base class.
Lets take an example:
Class B {
...
int iMem1;
int iMem2;
}
Class D: public B {
...
int iMem;
}
In this case, sizeof(D) is will also include the size of B. So it will be 12 bytes.
The existence of virtual function(s)
Existence of virtual function(s) will add 4 bytes of virtual table pointer in the class, which will be added to size of class. Again, in this case, if the base class of the class already has virtual function(s) either directly or through its base class, then this additional virtual function won't add anything to the size of the class. Virtual table pointer will be common across the class hierarchy. That is
class Base {
public:
...
virtual void SomeFunction(...);
private:
int iAMem
};
class Derived : public Base {
...
virtual void SomeOtherFunction(...);
private:
int iBMem
};
In the example above, sizeof(Base) will be 8 bytes--that is sizeof(int iAMem) + sizeof(vptr). sizeof(Derived) will be 12 bytes, that is sizeof(int iBMem) + sizeof(Derived). Notice that the existence of virtual functions in class Derived won't add anything more. Now Derived will set the vptr to its own virtual function table.
Compiler being used
In some scenarios, the size of a class object can be compiler specific. Lets take one example:
class BaseClass {
int a;
char c;
};
class DerivedClass : public BaseClass {
char d;
int i;
};
If compiled with the Microsoft C++ compiler, the size of DerivedClass is 16 bytes. If compiled with gcc (either c++ or g++), size of DerivedClass is 12 bytes.
The reason for sizeof(DerivedClass) being 16 bytes in MC++ is that it starts each class with a 4 byte aligned address so that accessing the member of that class will be easy (again, the memory read/write cycle).
Mode of inheritance (virtual inheritance)
In C++, sometimes we have to use virtual inheritance for some reasons. (One classic example is the implementation of final class in C++.) When we use virtual inheritance, there will be the overhead of 4 bytes for a virtual base class pointer in that class.
class ABase{
int iMem;
};
class BBase : public virtual ABase {
int iMem;
};
class CBase : public virtual ABase {
int iMem;
};
class ABCDerived : public BBase, public CBase {
int iMem;
};
And if you check the size of these classes, it will be:
Size of ABase : 4
Size of BBase : 12
Size of CBase : 12
Size of ABCDerived : 24
Because BBase and CBase are dervied from ABase virtually, they will also have an virtual base pointer. So, 4 bytes will be added to the size of the class (BBase and CBase). That is sizeof ABase + size of int + sizeof Virtual Base pointer.
Size of ABCDerived will be 24 (not 28 = sizeof (BBase + CBase + int member)) because it will maintain only one Virtual Base pointer (Same way of maintaining virtual table pointer).
Why is the size of an empty class not zero?
To ensure that the addresses of two different objects will be different. For the same reason, "new" always returns pointers to distinct objects. Consider:
class Empty { };
void f()
{
Empty a, b;
if (&a == &b) cout << "impossible: report error to compiler supplier";
Empty* p1 = new Empty;
Empty* p2 = new Empty;
if (p1 == p2) cout << "impossible: report error to compiler supplier";
}
There is an interesting rule that says that an empty base class need not be represented by a separate byte:
struct X : Empty {
int a;
// ...
};
void f(X* p)
{
void* p1 = p;
void* p2 = &p->a;
if (p1 == p2) cout << "nice: good optimizer";
}
This optimization is safe and can be most useful. It allows a programmer to use empty classes to represent very simple concepts without overhead. Some current compilers provide this "empty base class optimization".
________________________________________
Why do I have to put the data in my class declarations?
________________________________________
You don't. If you don't want data in an interface, don't put it in the class that defines the interface. Put it in derived classes instead. See, Why do my compiles take so long?.
Sometimes, you do want to have representation data in a class. Consider class complex:
template class complex {
public:
complex() : re(0), im(0) { }
complex(Scalar r) : re(r), im(0) { }
complex(Scalar r, Scalar i) : re(r), im(i) { }
// ...
complex& operator+=(const complex& a)
{ re+=a.re; im+=a.im; return *this; }
// ...
private:
Scalar re, im;
};
This type is designed to be used much as a built-in type and the representation is needed in the declaration to make it possible to create genuinely local objects (i.e. objects that are allocated on the stack and not on a heap) and to ensure proper inlining of simple operations. Genuinely local objects and inlining is necessary to get the performance of complex close to what is provided in languages with a built-in complex type.
________________________________________
________________________________________
Why can't I initialize my static member data in my constructor's initialization list?
________________________________________
Because you must explicitly define your class's static data members.
Fred.h:
class Fred {
public:
Fred();
...
private:
int i_;
static int j_;
};
Fred.cpp (or Fred.C or whatever):
Fred::Fred()
: i_(10) // OK: you can (and should) initialize member data this way
, j_(42) // Error: you cannot initialize static member data like this
{
...
}
// You must define static data members this way:
int Fred::j_ = 42;
________________________________________
Why are classes with static data members getting linker errors?
________________________________________
Because static data members must be explicitly defined in exactly one compilation unit. If you didn't do this, you'll probably get an "undefined external" linker error. For example:
// Fred.h
class Fred {
public:
...
private:
static int j_; // Declares static data member Fred::j_
...
};
The linker will holler at you ("Fred::j_ is not defined") unless you define (as opposed to merely declare) Fred::j_ in (exactly) one of your source files:
// Fred.cpp
#include "Fred.h"
int Fred::j_ = some_expression_evaluating_to_an_int;
// Alternatively, if you wish to use the implicit 0 value for static ints:
// int Fred::j_;
The usual place to define static data members of class Fred is file Fred.cpp (or Fred.C or whatever source file extension you use).
________________________________________
How are C++ objects laid out in memory?
________________________________________
Like C, C++ doesn't define layouts, just semantic constraints that must be met. Therefore different implementations do things differently. Unfortunately, the best explanation I know of is in a book that is otherwise outdated and doesn't describe any current C++ implementation: The Annotated C++ Reference Manual (usually called the ARM). It has diagrams of key layout examples. There is a very brief explanation in Chapter 2 of TC++PL.
Basically, C++ constructs objects simply by concatenating sub objects. Thus
struct A { int a,b; };
is represented by two ints next to each other, and
struct B : A { int c; };
is represented by an A followed by an int; that is, by three ints next to each other.
Virtual functions are typically implemented by adding a pointer (the vptr) to each object of a class with virtual functions. This pointer points to the appropriate table of functions (the vtbl). Each class has its own vtbl shared by all objects of that class.
________________________________________
________________________________________
What is a function object?
________________________________________
An object that in some way behaves like a function, of course. Typically, that would mean an object of a class that defines the application operator - operator().
A function object is a more general concept than a function because a function object can have state that persist across several calls (like a static local variable) and can be initialized and examined from outside the object (unlike a static local variable). For example:
class Sum {
int val;
public:
Sum(int i) :val(i) { }
operator int() const { return val; } // extract value
int operator()(int i) { return val+=i; } // application
};
void f(vector v)
{
Sum s = 0; // initial value 0
s = for_each(v.begin(), v.end(), s); // gather the sum of all elements
cout << "the sum is " <<>
// or even:
cout << "the sum is " <<>
}
Note that a function object with an inline application operator inlines beautifully because there are no pointers involved that might confuse optimizers. To contrast: current optimizers are rarely (never?) able to inline a call through a pointer to function.
Function objects are extensively used to provide flexibility in the standard library.
________________________________________
Why doesn't C++ have a universal class Object?
________________________________________
We don't need one: generic programming provides statically type safe alternatives in most cases. Other cases are handled using multiple inheritance.
There is no useful universal class: a truly universal carries no semantics of its own.
A "universal" class encourages sloppy thinking about types and interfaces and leads to excess run-time checking.
Using a universal base class implies cost: Objects must be heap-allocated to be polymorphic; that implies memory and access cost. Heap objects don't naturally support copy semantics. Heap objects don't support simple scoped behavior (which complicates resource management). A universal base class encourages use of dynamic_cast and other run-time checking.
How do I define an in-class constant?
________________________________________
If you want a constant that you can use in a constant expression, say as an array bound, you have two choices:
class X {
static const int c1 = 7;
enum { c2 = 19 };
char v1[c1];
char v2[c2];
// ...
};
At first glance, the declaration of c1 seems cleaner, but note that to use that in-class initialization syntax, the constant must be a static const of integral or enumeration type initialized by a constant expression. That's quite restrictive:
class Y {
const int c3 = 7; // error: not static
static int c4 = 7; // error: not const
static const float c5 = 7; // error not integral
};
I tend to use the "enum trick" because it's portable and doesn't tempt me to use non-standard extensions of the in-class initialization syntax.
So why do these inconvenient restrictions exist? A class is typically declared in a header file and a header file is typically included into many translation units. However, to avoid complicated linker rules, C++ requires that every object has a unique definition. That rule would be broken if C++ allowed in-class definition of entities that needed to be stored in memory as objects. See D&E for an explanation of C++'s design tradeoffs.
You have more flexibility if the const isn't needed for use in a constant expression:
class Z {
static char* p; // initialize in definition
const int i; // initialize in constructor
public:
Z(int ii) :i(ii) { }
};
char* Z::p = "hello, there";
You can take the address of a static member if (and only if) it has an out-of-class definition:
class AE {
// ...
public:
static const int c6 = 7;
static const int c7 = 31;
};
const int AE::c7; // definition
int f()
{
const int* p1 = &AE::c6; // error: c6 not an lvalue
const int* p2 = &AE::c7; // ok
// ...
}
________________________________________
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).
==============================================================================
Q45: What is a `const member function'?
A: A const member function is a promise to the caller not to change the object.
Put the word `const' after the member function's signature; ex:
class X {
//...
void f() const;
};
Some programmers feel this should be a signal to the compiler that the raw bits
of the object's `struct' aren't going to change, others feel it means the
*abstract* (client-visible) state of the object isn't going to change. C++
compilers aren't allowed to assume the bitwise const, since a non-const alias
could exist which could modify the state of the object (gluing a `const' ptr to
an object doesn't promise the object won't change; it only promises that the
object won't change **via that pointer**).
I talked to Jonathan Shopiro at the C++AtWork conference, and he confirmed that
the above view has been ratified by the ANSI-C++ standards board. This doesn't
make it a `perfect' view, but it will make it `the standard' view.
See the next few questions for more.
==============================================================================
Q46: What is an `inspector'? What is a `mutator'?
A: An inspector inspects and a mutator mutates. These different categories of
member fns are distinguished by whether the member fn is `const' or not.
________________________________________
Why isn't the destructor called at the end of scope?
________________________________________
The simple answer is "of course it is!", but have a look at the kind of example that often accompany that question:
void f()
{
X* p = new X;
// use p
}
That is, there was some (mistaken) assumption that the object created by "new" would be destroyed at the end of a function.
Basically, you should only use "new" if you want an object to live beyond the lifetime of the scope you create it in. That done, you need to use "delete" to destroy it. For example:
X* g(int i) { /* ... */ return new X(i); } // the X outlives the call of g()
void h(int i)
{
X* p = g(i);
// ...
delete p;
}
If you want an object to live in a scope only, don't use "new" but simply define a variable:
{
ClassName x;
// use x
}
The variable is implicitly destroyed at the end of the scope.
Code that creates an object using new and then deletes it at the end of the same scope is ugly, error-prone, and inefficient. For example:
void fct() // ugly, error-prone, and inefficient
{
X* p = new X;
// use p
delete p;
}
How can I handle a constructor that fails?
________________________________________
throw an exception. Constructors don't have a return type, so it's not possible to use return codes. The best way to signal constructor failure is therefore to throw an exception.
________________________________________
How can I handle a destructor that fails?
________________________________________
Write a message to a log-file. But do not throw an exception.
The C++ rule is that you must never throw an exception from a destructor that is being called during the "stack unwinding" process of another exception. For example, if someone says throw Foo(), the stack will be unwound so all the stack frames between the throw Foo() and the } catch (Foo e) { will get popped. This is called stack unwinding.
During stack unwinding, all the local objects in all those stack frames are destructed. If one of those destructors throws an exception (say it throws a Bar object), the C++ runtime system is in a no-win situation: should it ignore the Bar and end up in the } catch (Foo e) { where it was originally headed? Should it ignore the Foo and look for a } catch (Bar e) { handler? There is no good answer -- either choice loses information.
So the C++ language guarantees that it will call terminate() at this point, and terminate() kills the process. Bang you're dead.
________________________________________
What is Virtual Destructor?
________________________________________
Using virtual destructors, you can destroy objects without knowing their type - the correct destructor for the object is invoked using the virtual function mechanism. Note that destructors can also be declared as pure virtual functions for abstract classes.
if someone will derive from your class, and if someone will say "new Derived", where "Derived" is derived from your class, and if someone will say delete p, where the actual object's type is "Derived" but the pointer p's type is your class.
________________________________________
Can a copy constructor accept an object of the same class as parameter, instead of reference of the object?
________________________________________
No. It is specified in the definition of the copy constructor itself. It should generate an error if a programmer specifies a copy constructor with a first argument that is an object and not a reference.
________________________________________
Why should I use inline functions instead of plain old #define macros?
________________________________________
Because #define macros are evil in 4 different ways: evil#1, evil#2, evil#3, and evil#4. Sometimes you should use them anyway, but they're still evil.
Unlike #define macros, inline functions avoid infamous macro errors since inline functions always evaluate every argument exactly once. In other words, invoking an inline function is semantically just like invoking a regular function, only faster:
// A macro that returns the absolute value of i
#define unsafe(i) \
( (i) >= 0 ? (i) : -(i) )
// An inline function that returns the absolute value of i
inline
int safe(int i)
{
return i >= 0 ? i : -i;
}
int f();
void userCode(int x)
{
int ans;
ans = unsafe(x++); // Error! x is incremented twice
ans = unsafe(f()); // Danger! f() is called twice
ans = safe(x++); // Correct! x is incremented once
ans = safe(f()); // Correct! f() is called once
}
Also unlike macros, argument types are checked, and necessary conversions are performed correctly.
Macros are bad for your health; don't use them unless you have to.
________________________________________
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.
________________________________________
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.
________________________________________
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. 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.
________________________________________
With inline member functions that are defined outside the class, is it best to put the inline keyword next to the declaration within the class body, next to the definition outside the class body, or both?
________________________________________
Best practice: only in the definition outside the class body.
class Foo {
public:
void method(); © best practice: don't put the inline keyword here
...
};
inline void Foo::method() © best practice: put the inline keyword here
{ ... }
Here's the basic idea:
The public: part of the class body is where you describe the observable semantics of a class, its public member functions, its friend functions, and anything else exported by the class. Try not to provide any inklings of anything that can't be observed from the caller's code.
The other parts of the class, including non-public: part of the class body, the definitions of your member and friend functions, etc. are pure implementation. Try not to describe any observable semantics that were not already described in the class's public: part.
From a practical standpoint, this separation makes life easier and safer for your users. Say Chuck wants to simply "use" your class. Because you read this FAQ and used the above separation, Chuck can read your class's public: part and see everything he needs to see and nothing he doesn't need to see. His life is easier because he needs to look in only one spot, and his life is safer because his pure mind isn't polluted by implementation minutiae.
Back to inline-ness: the decision of whether a function is or is not inline is an implementation detail that does not change the observable semantics (the "meaning") of a call. Therefore the inline keyword should go next to the function's definition, not within the class's public: part.
NOTE: most people use the terms "declaration" and "definition" to differentiate the above two places. For example, they might say, "Should I put the inline keyword next to the declaration or the definition?" Unfortunately that usage is sloppy and somebody out there will eventually gig you for it. The people who gig you are probably insecure, pathetic wannabes who know they're not good enough to actually acomplish something with their lives, nonetheless you might as well learn the correct terminology to avoid getting gigged. Here it is: every definition is also a declaration. This means using the two as if they are mutually exclusive would be like asking which is heavier, steel or metal? Almost everybody will know what you mean if you use "definition" as if it is the opposite of "declaration," and only the worst of the techie weenies will gig you for it, but at least you now know how to use the terms correctly.
________________________________________
Can one constructor of a class call another constructor of the same class to initialize the this object?
________________________________________
Nope.
Let's work an example. Suppose you want your constructor Foo::Foo(char) to call another constructor of the same class, say Foo::Foo(char,int), in order that Foo::Foo(char,int) would help initialize the this object. Unfortunately there's no way to do this in C++.
Some people do it anyway. Unfortunately it doesn't do what they want. For example, the line Foo(x, 0); does not call Foo::Foo(char,int) on the this object. Instead it calls Foo::Foo(char,int) to initialize a temporary, local object (not this), then it immediately destructs that temporary when control flows over the ;.
class Foo {
public:
Foo(char x);
Foo(char x, int y);
...
};
Foo::Foo(char x)
{
...
Foo(x, 0); // this line does NOT help initialize the this object!!
...
}
You can sometimes combine two constructors via a default parameter:
class Foo {
public:
Foo(char x, int y=0); // this line combines the two constructors
...
};
If that doesn't work, e.g., if there isn't an appropriate default parameter that combines the two constructors, sometimes you can share their common code in a private init() member function:
class Foo {
public:
Foo(char x);
Foo(char x, int y);
...
private:
void init(char x, int y);
};
Foo::Foo(char x)
{
init(x, int(x) + 7);
...
}
Foo::Foo(char x, int y)
{
init(x, y);
...
}
void Foo::init(char x, int y)
{
...
}
BTW do NOT try to achieve this via placement new. Some people think they can say new(this) Foo(x, int(x)+7) within the body of Foo::Foo(char). However that is bad, bad, bad. Please don't write me and tell me that it seems to work on your particular version of your particular compiler; it's bad. Constructors do a bunch of little magical things behind the scenes, but that bad technique steps on those partially constructed bits. Just say no.
________________________________________
Is the default constructor for Fred always Fred::Fred()?
________________________________________
No. A "default constructor" is a constructor that can be called with no arguments. One example of this is a constructor that takes no parameters:
class Fred {
public:
Fred(); // Default constructor: can be called with no args
...
};
Another example of a "default constructor" is one that can take arguments, provided they are given default values:
class Fred {
public:
Fred(int i=3, int j=5); // Default constructor: can be called with no args
...
};
________________________________________
Which constructor gets called when I create an array of Fred objects?
________________________________________
Fred's default constructor (except as discussed below).
class Fred {
public:
Fred();
...
};
int main()
{
Fred a[10]; ¡lls the default constructor 10 times
Fred* p = new Fred[10]; ¡lls the default constructor 10 times
...
}
If your class doesn't have a default constructor, you'll get a compile-time error when you attempt to create an array using the above simple syntax:
class Fred {
public:
Fred(int i, int j); ¡sume there is no default constructor
...
};
int main()
{
Fred a[10]; ¡󠅒ROR: Fred doesn't have a default constructor
Fred* p = new Fred[10]; ¡󠅒ROR: Fred doesn't have a default constructor
...
}
However, even if your class already has a default constructor, you should try to use std::vector rather than an array (arrays are evil). std::vector lets you decide to use any constructor, not just the default constructor:
#include
int main()
{
std::vector a(10, Fred(5,7)); ¡e 10 Fred objects in std::vector a will be initialized with Fred(5,7)
...
}
Even though you ought to use a std::vector rather than an array, there are times when an array might be the right thing to do, and for those, you might need the "explicit initialization of arrays" syntax. Here's how:
class Fred {
public:
Fred(int i, int j); ¡sume there is no default constructor
...
};
int main()
{
Fred a[10] = {
Fred(5,7), Fred(5,7), Fred(5,7), Fred(5,7), Fred(5,7), // The 10 Fred objects are
Fred(5,7), Fred(5,7), Fred(5,7), Fred(5,7), Fred(5,7) // initialized using Fred(5,7)
};
...
}
Of course you don't have to do Fred(5,7) for every entry ¡ª you can put in any numbers you want, even parameters or other variables.
Finally, you can use placement-new to manually initialize the elements of the array. Warning: it's ugly: the raw array can't be of type Fred, so you'll need a bunch of pointer-casts to do things like compute array index operations. Warning: it's compiler- and hardware-dependent: you'll need to make sure the storage is aligned with an alignment that is at least as strict as is required for objects of class Fred. Warning: it's tedious to make it exception-safe: you'll need to manually destruct the elements, including in the case when an exception is thrown part-way through the loop that calls the constructors. But if you really want to do it anyway, read up on placement-new. (BTW placement-new is the magic that is used inside of std::vector. The complexity of getting everything right is yet another reason to use std::vector.)
By the way, did I ever mention that arrays are evil? Or did I mention that you ought to use a std::vector unless there is a compelling reason to use an array?
________________________________________
Should my constructors use "initialization lists" or "assignment"?
________________________________________
Initialization lists. In fact, constructors should initialize as a rule all member objects in the initialization list. One exception is discussed further down.
Consider the following constructor that initializes member object x_ using an initialization list: Fred::Fred() : x_(whatever) { }. The most common benefit of doing this is improved performance. For example, if the expression whatever is the same type as member variable x_, the result of the whatever expression is constructed directly inside x_ — the compiler does not make a separate copy of the object. Even if the types are not the same, the compiler is usually able to do a better job with initialization lists than with assignments.
The other (inefficient) way to build constructors is via assignment, such as: Fred::Fred() { x_ = whatever; }. In this case the expression whatever causes a separate, temporary object to be created, and this temporary object is passed into the x_ object's assignment operator. Then that temporary object is destructed at the ;. That's inefficient.
As if that wasn't bad enough, there's another source of inefficiency when using assignment in a constructor: the member object will get fully constructed by its default constructor, and this might, for example, allocate some default amount of memory or open some default file. All this work could be for naught if the whatever expression and/or assignment operator causes the object to close that file and/or release that memory (e.g., if the default constructor didn't allocate a large enough pool of memory or if it opened the wrong file).
Conclusion: All other things being equal, your code will run faster if you use initialization lists rather than assignment.
Note: There is no performance difference if the type of x_ is some built-in/intrinsic type, such as int or char* or float. But even in these cases, my personal preference is to set those data members in the initialization list rather than via assignment for consistency. Another symmetry argument in favor of using initialization lists even for built-in/intrinsic types: non-static const and non-static reference data members can't be assigned a value in the constructor, so for symmetry it makes sense to initialize everything in the initialization list.
Now for the exceptions. Every rule has exceptions (hmmm; does "every rule has exceptions" have exceptions? reminds me of G's Incompleteness Theorems), and there are a couple of exceptions to the "use initialization lists" rule. Bottom line is to use common sense: if it's cheaper, better, faster, etc. to not use them, then by all means, don't use them. This might happen when your class has two constructors that need to initialize the this object's data members in different orders. Or it might happen when two data members are self-referential. Or when a data-member needs a reference to the this object, and you want to avoid a compiler warning about using the this keyword prior to the { that begins the constructor's body (when your particular compiler happens to issue that particular warning). Or when you need to do an if/throw test on a variable (parameter, global, etc.) prior to using that variable to initialize one of your this members. This list is not exhaustive; please don't write me asking me to add another "Or when...". The point is simply this: use common sense.
________________________________________
What is the "Named Constructor Idiom"?
________________________________________
A technique that provides more intuitive and/or safer construction operations for users of your class.
The problem is that constructors always have the same name as the class. Therefore the only way to differentiate between the various constructors of a class is by the parameter list. But if there are lots of constructors, the differences between them become somewhat subtle and error prone.
With the Named Constructor Idiom, you declare all the class's constructors in the private or protected sections, and you provide public static methods that return an object. These static methods are the so-called "Named Constructors." In general there is one such static method for each different way to construct an object.
For example, suppose we are building a Point class that represents a position on the X-Y plane. Turns out there are two common ways to specify a 2-space coordinate: rectangular coordinates (X+Y), polar coordinates (Radius+Angle). (Don't worry if you can't remember these; the point isn't the particulars of coordinate systems; the point is that there are several ways to create a Point object.) Unfortunately the parameters for these two coordinate systems are the same: two floats. This would create an ambiguity error in the overloaded constructors:
class Point {
public:
Point(float x, float y); // Rectangular coordinates
Point(float r, float a); // Polar coordinates (radius and angle)
// ERROR: Overload is Ambiguous: Point::Point(float,float)
};
int main()
{
Point p = Point(5.7, 1.2); // Ambiguous: Which coordinate system?
...
}
One way to solve this ambiguity is to use the Named Constructor Idiom:
#include // To get sin() and cos()
class Point {
public:
static Point rectangular(float x, float y); // Rectangular coord's
static Point polar(float radius, float angle); // Polar coordinates
// These static methods are the so-called "named constructors"
...
private:
Point(float x, float y); // Rectangular coordinates
float x_, y_;
};
inline Point::Point(float x, float y)
: x_(x), y_(y) { }
inline Point Point::rectangular(float x, float y)
{ return Point(x, y); }
inline Point Point::polar(float radius, float angle)
{ return Point(radius*cos(angle), radius*sin(angle)); }
Now the users of Point have a clear and unambiguous syntax for creating Points in either coordinate system:
int main()
{
Point p1 = Point::rectangular(5.7, 1.2); // Obviously rectangular
Point p2 = Point::polar(5.7, 1.2); // Obviously polar
...
}
Make sure your constructors are in the protected section if you expect Point to have derived classes.
The Named Constructor Idiom can also be used to make sure your objects are always created via new.
Note that the Named Constructor Idiom, at least as implemented above, is just as fast as directly calling a constructor — modern compilers will not make any extra copies of your object.
________________________________________
Why can't I initialize my static member data in my constructor's initialization list?
________________________________________
Because you must explicitly define your class's static data members.
Fred.h:
class Fred {
public:
Fred();
...
private:
int i_;
static int j_;
};
Fred.cpp (or Fred.C or whatever):
Fred::Fred()
: i_(10) // OK: you can (and should) initialize member data this way
, j_(42) // Error: you cannot initialize static member data like this
{
...
}
// You must define static data members this way:
int Fred::j_ = 42;
________________________________________
Why are classes with static data members getting linker errors?
________________________________________
Because static data members must be explicitly defined in exactly one compilation unit. If you didn't do this, you'll probably get an "undefined external" linker error. For example:
// Fred.h
class Fred {
public:
...
private:
static int j_; // Declares static data member Fred::j_
...
};
The linker will holler at you ("Fred::j_ is not defined") unless you define (as opposed to merely declare) Fred::j_ in (exactly) one of your source files:
// Fred.cpp
#include "Fred.h"
int Fred::j_ = some_expression_evaluating_to_an_int;
// Alternatively, if you wish to use the implicit 0 value for static ints:
// int Fred::j_;
The usual place to define static data members of class Fred is file Fred.cpp (or Fred.C or whatever source file extension you use).
________________________________________
What's the "static initialization order fiasco"?
________________________________________
A subtle way to crash your program.
The static initialization order fiasco is a very subtle and commonly misunderstood aspect of C++. Unfortunately it's very hard to detect — the errors occur before main() begins.
In short, suppose you have two static objects x and y which exist in separate source files, say x.cpp and y.cpp. Suppose further that the initialization for the y object (typically the y object's constructor) calls some method on the x object.
That's it. It's that simple.
The tragedy is that you have a 50%-50% chance of dying. If the compilation unit for x.cpp happens to get initialized first, all is well. But if the compilation unit for y.cpp get initialized first, then y's initialization will get run before x's initialization, and you're toast. E.g., y's constructor could call a method on the x object, yet the x object hasn't yet been constructed.
I hear they're hiring down at McDonalds. Enjoy your new job flipping burgers.
If you think it's "exciting" to play Russian Roulette with live rounds in half the chambers, you can stop reading here. On the other hand if you like to improve your chances of survival by preventing disasters in a systematic way, you probably want to read the next FAQ.
Note: The static initialization order fiasco can also, in some cases, apply to built-in/intrinsic types.
________________________________________
How do I prevent the "static initialization order fiasco"?
________________________________________
Use the "construct on first use" idiom, which simply means to wrap your static object inside a function.
For example, suppose you have two classes, Fred and Barney. There is a global Fred object called x, and a global Barney object called y. Barney's constructor invokes the goBowling() method on the x object. The file x.cpp defines the x object:
// File x.cpp
#include "Fred.h"
Fred x;
The file y.cpp defines the y object:
// File y.cpp
#include "Barney.h"
Barney y;
For completeness the Barney constructor might look something like this:
// File Barney.cpp
#include "Barney.h"
Barney::Barney()
{
...
x.goBowling();
...
}
As described above, the disaster occurs if y is constructed before x, which happens 50% of the time since they're in different source files.
There are many solutions to this problem, but a very simple and completely portable solution is to replace the global Fred object, x, with a global function, x(), that returns the Fred object by reference.
// File x.cpp
#include "Fred.h"
Fred& x()
{
static Fred* ans = new Fred();
return *ans;
}
Since static local objects are constructed the first time control flows over their declaration (only), the above new Fred() statement will only happen once: the first time x() is called. Every subsequent call will return the same Fred object (the one pointed to by ans). Then all you do is change your usages of x to x():
// File Barney.cpp
#include "Barney.h"
Barney::Barney()
{
...
x().goBowling();
...
}
This is called the Construct On First Use Idiom because it does just that: the global Fred object is constructed on its first use.
The downside of this approach is that the Fred object is never destructed. There is another technique that answers this concern, but it needs to be used with care since it creates the possibility of another (equally nasty) problem.
Note: The static initialization order fiasco can also, in some cases, apply to built-in/intrinsic types.
________________________________________
Why doesn't the construct-on-first-use idiom use a static object instead of a static pointer?
________________________________________
Short answer: it's possible to use a static object rather than a static pointer, but doing so opens up another (equally subtle, equally nasty) problem.
Long answer: sometimes people worry about the fact that the previous solution "leaks." In many cases, this is not a problem, but it is a problem in some cases. Note: even though the object pointed to by ans in the previous FAQ is never deleted, the memory doesn't actually "leak" when the program exits since the operating system automatically reclaims all the memory in a program's heap when that program exits. In other words, the only time you'd need to worry about this is when the destructor for the Fred object performs some important action (such as writing something to a file) that must occur sometime while the program is exiting.
In those cases where the construct-on-first-use object (the Fred, in this case) needs to eventually get destructed, you might consider changing function x() as follows:
// File x.cpp
#include "Fred.h"
Fred& x()
{
static Fred ans; // was static Fred* ans = new Fred();
return ans; // was return *ans;
}
However there is (or rather, may be) a rather subtle problem with this change. To understand this potential problem, let's remember why we're doing all this in the first place: we need to make 100% sure our static object (a) gets constructed prior to its first use and (b) doesn't get destructed until after its last use. Obviously it would be a disaster if any static object got used either before construction or after destruction. The message here is that you need to worry about two situations (static initialization and static deinitialization), not just one.
By changing the declaration from static Fred* ans = new Fred(); to static Fred ans;, we still correctly handle the initialization situation but we no longer handle the deinitialization situation. For example, if there are 3 static objects, say a, b and c, that use ans during their destructors, the only way to avoid a static deinitialization disaster is if ans is destructed after all three.
The point is simple: if there are any other static objects whose destructors might use ans after ans is destructed, bang, you're dead. If the constructors of a, b and c use ans, you should normally be okay since the runtime system will, during static deinitialization, destruct ans after the last of those three objects is destructed. However if a and/or b and/or c fail to use ans in their constructors and/or if any code anywhere gets the address of ans and hands it to some other static object, all bets are off and you have to be very, very careful.
There is a third approach that handles both the static initialization and static deinitialization situations, but it has other non-trivial costs. I'm too lazy (and busy!) to write any more FAQs today so if you're interested in that third approach, you'll have to buy a book that describes that third approach in detail. The C++ FAQs book is one of those books, and it also gives the cost/benefit analysis to decide if/when that third approach should be used.
________________________________________
How do I prevent the "static initialization order fiasco" for my static data members?
________________________________________
Just use the same technique just described, but this time use a static member function rather than a global function.
Suppose you have a class X that has a static Fred object:
// File X.h
class X {
public:
...
private:
static Fred x_;
};
Naturally this static member is initialized separately:
// File X.cpp
#include "X.h"
Fred X::x_;
Naturally also the Fred object will be used in one or more of X's methods:
void X::someMethod()
{
x_.goBowling();
}
But now the "disaster scenario" is if someone somewhere somehow calls this method before the Fred object gets constructed. For example, if someone else creates a static X object and invokes its someMethod() method during static initialization, then you're at the mercy of the compiler as to whether the compiler will construct X::x_ before or after the someMethod() is called. (Note that the ANSI/ISO C++ committee is working on this problem, but compilers aren't yet generally available that handle these changes; watch this space for an update in the future.)
In any event, it's always portable and safe to change the X::x_ static data member into a static member function:
// File X.h
class X {
public:
...
private:
static Fred& x();
};
Naturally this static member is initialized separately:
// File X.cpp
#include "X.h"
Fred& X::x()
{
static Fred* ans = new Fred();
return *ans;
}
Then you simply change any usages of x_ to x():
void X::someMethod()
{
x().goBowling();
}
If you're super performance sensitive and you're concerned about the overhead of an extra function call on each invocation of X::someMethod() you can set up a static Fred& instead. As you recall, static local are only initialized once (the first time control flows over their declaration), so this will call X::x() only once: the first time X::someMethod() is called:
void X::someMethod()
{
static Fred& x = X::x();
x.goBowling();
}
Note: The static initialization order fiasco can also, in some cases, apply to built-in/intrinsic types.
________________________________________
Why am I getting an error after declaring a Foo object via Foo x(Bar())?
________________________________________
Because that doesn't create a Foo object - it declares a non-member function that returns a Foo object.
This is really going to hurt; you might want to sit down.
First, here's a better explanation of the problem. Suppose there is a class called Bar that has a default ctor. This might even be a library class such as std::string, but for now we'll just call it Bar:
class Bar {
public:
Bar();
...
};
Now suppose there's another class called Foo that has a ctor that takes a Bar. As before, this might be defined by someone other than you.
class Foo {
public:
Foo(const Bar& b); // or perhaps Foo(Bar b)
...
void blah();
...
};
Now you want to create a Foo object using a temporary Bar. In other words, you want to create an object via Bar(), and pass that to the Foo ctor to create a local Foo object called x:
void yourCode()
{
Foo x(Bar()); ¡u think this creates a Foo object called x...
x.blah(); ¡.but it doesn't, so this line gives you a bizarre error message
...
}
It's a long story, but the solution (hope you're sitting down!) is to use = in your declaration:
void yourCode()
{
Foo x = Foo(Bar()); ¡s, Virginia, that thar syntax really works
x.blah(); ¡hhh, this works now ¡ª no more error messages
...
}
Here's why that happens (this part is optional; only read it if you think your future as a programmer is worth two minutes of your precious time today): When the compiler sees Foo x(Bar()), it thinks that the Bar() part is declaring a non-member function that returns a Bar object, so it thinks you are declaring the existence of a function called x that returns a Foo and that takes as a single parameter of type "non-member function that takes nothing and returns a Bar."
Now here's the sad part. In fact it's pathetic. Some mindless drone out there is going to skip that last paragraph, then they're going to impose a bizarre, incorrect, irrelevant, and just plain stupid coding standard that says something like, "Never create temporaries using a default constructor" or "Always use = in all initializations" or something else equally inane. If that's you, please fire yourself before you do any more damage. Those who don't understand the problem shouldn't tell others how to solve it. Harumph.
(Okay, that was mostly tongue in cheek. But there's a grain of truth in it. The real problem is that people tend to worship consistency, and they tend to extrapolate from the obscure to the common. That's not wise.)
Follow-up: if your Foo::Foo(const Bar&) constructor is not explicit, and if Foo's copy constructor is accessible, you can use this syntax instead: Foo x = Bar();.
________________________________________
What's the order that local objects are destructed?
________________________________________
In reverse order of construction: First constructed, last destructed.
In the following example, b's destructor will be executed first, then a's destructor:
void userCode()
{
Fred a;
Fred b;
...
}
________________________________________
What's the order that objects in an array are destructed?
________________________________________
In reverse order of construction: First constructed, last destructed.
In the following example, the order for destructors will be a[9], a[8], ..., a[1], a[0]:
void userCode()
{
Fred a[10];
...
}
________________________________________
Should I explicitly call a destructor on a local variable?
________________________________________
No!
The destructor will get called again at the close } of the block in which the local was created. This is a guarantee of the language; it happens automagically; there's no way to stop it from happening. But you can get really bad results from calling a destructor on the same object a second time! Bang! You're dead!
What if I want a local to "die" before the close } of the scope in which it was created? Can I call a destructor on a local if I really want to?
________________________________________
No! [For context, please read the previous FAQ].
Suppose the (desirable) side effect of destructing a local File object is to close the File. Now suppose you have an object f of a class File and you want File f to be closed before the end of the scope (i.e., the }) of the scope of object f:
void someCode()
{
File f;
...insert code that should execute when f is still open...
© We want the side-effect of f's destructor here!
...insert code that should execute after f is closed...
}
There is a simple solution to this problem. But in the mean time, remember: Do not explicitly call the destructor!
________________________________________
OK, OK already; I won't explicitly call the destructor of a local; but how do I handle the above situation?
________________________________________
Simply wrap the extent of the lifetime of the local in an artificial block {...}:
void someCode()
{
{
File f;
...insert code that should execute when f is still open...
}© f's destructor will automagically be called here!
...insert code here that should execute after f is closed...
}
________________________________________
What if I can't wrap the local in an artificial block?
________________________________________
Most of the time, you can limit the lifetime of a local by wrapping the local in an artificial block ({...}). But if for some reason you can't do that, add a member function that has a similar effect as the destructor. But do not call the destructor itself!
For example, in the case of class File, you might add a close() method. Typically the destructor will simply call this close() method. Note that the close() method will need to mark the File object so a subsequent call won't re-close an already-closed File. E.g., it might set the fileHandle_ data member to some nonsensical value such as -1, and it might check at the beginning to see if the fileHandle_ is already equal to -1:
class File {
public:
void close();
~File();
...
private:
int fileHandle_; // fileHandle_ >= 0 if/only-if it's open
};
File::~File()
{
close();
}
void File::close()
{
if (fileHandle_ >= 0) {
...insert code to call the OS to close the file...
fileHandle_ = -1;
}
}
Note that the other File methods may also need to check if the fileHandle_ is -1 (i.e., check if the File is closed).
Note also that any constructors that don't actually open a file should set fileHandle_ to -1.
________________________________________
But can I explicitly call a destructor if I've allocated my object with new?
________________________________________
Probably not.
Unless you used placement new, you should simply delete the object rather than explicitly calling the destructor. For example, suppose you allocated the object via a typical new expression:
Fred* p = new Fred();
Then the destructor Fred::~Fred() will automagically get called when you delete it via:
delete p; // Automagically calls p->~Fred()
You should not explicitly call the destructor, since doing so won't release the memory that was allocated for the Fred object itself. Remember: delete p does two things: it calls the destructor and it deallocates the memory.
________________________________________
What is "placement new" and why would I use it?
________________________________________
There are many uses of placement new. The simplest use is to place an object at a particular location in memory. This is done by supplying the place as a pointer parameter to the new part of a new expression:
#include // Must #include this to use "placement new"
#include "Fred.h" // Declaration of class Fred
void someCode()
{
char memory[sizeof(Fred)]; // Line #1
void* place = memory; // Line #2
Fred* f = new(place) Fred(); // Line #3 (see "DANGER" below)
// The pointers f and place will be equal
...
}
Line #1 creates an array of sizeof(Fred) bytes of memory, which is big enough to hold a Fred object. Line #2 creates a pointer place that points to the first byte of this memory (experienced C programmers will note that this step was unnecessary; it's there only to make the code more obvious). Line #3 essentially just calls the constructor Fred::Fred(). The this pointer in the Fred constructor will be equal to place. The returned pointer f will therefore be equal to place.
ADVICE: Don't use this "placement new" syntax unless you have to. Use it only when you really care that an object is placed at a particular location in memory. For example, when your hardware has a memory-mapped I/O timer device, and you want to place a Clock object at that memory location.
DANGER: You are taking sole responsibility that the pointer you pass to the "placement new" operator points to a region of memory that is big enough and is properly aligned for the object type that you're creating. Neither the compiler nor the run-time system make any attempt to check whether you did this right. If your Fred class needs to be aligned on a 4 byte boundary but you supplied a location that isn't properly aligned, you can have a serious disaster on your hands (if you don't know what "alignment" means, please don't use the placement new syntax). You have been warned.
You are also solely responsible for destructing the placed object. This is done by explicitly calling the destructor:
void someCode()
{
char memory[sizeof(Fred)];
void* p = memory;
Fred* f = new(p) Fred();
...
f->~Fred(); // Explicitly call the destructor for the placed object
}
This is about the only time you ever explicitly call a destructor.
Note: there is a much cleaner but more sophisticated way of handling the destruction / deletion situation.
________________________________________
What is conversion constructor?
________________________________________
constructor with a single argument makes that constructor as conversion ctor and it can be used for type conversion.
for example:
class Boo
{
public:
Boo( int i );
};
Boo BooObject = 10 ; // assigning int 10 Boo object
No comments:
Post a Comment