Thursday, June 7, 2007

c++ default methods

http://www.cs.wisc.edu/~bolo/notes/code_notes/4methods.html

C++ Constructors, Destructors
and
Default Methods

Bolo


Background

Every C++ class has a minimum of 4 methods. They exist whether or not you create them. The methods are:


+---------------------------------------------------------+
|What Name |
+---------------------------------------------------------+
|Default Constructor A::A() |
|Copy Constructor A::A(const A &) |
|Assignment [const] A &A::operator=(const A &) |
|Destructor A::~A() |
+---------------------------------------------------------+

构造函数不能指定返回值!

The default copy constructor and assignment construc-
tors are to do a bit-wise copy of any non-class members of a
class. Whitespace (padding) between class members is not
copied. If a class contains any other classes, then the
copy constructor or assignment constructor for that class is
used instead of the bit-wise copy.


Constructor and Assignment Necessities

If a class contains a pointer, you must define your own
versions of them because the class is just an accident wait-
ing to happen. The first time a default copy constructor or
assignment operator goes off, the ownership of pointed-to
objects becomes questionable. If a class SHOULD NOT BE
COPIED, then provide unimplimented, private copy construc-
tors and assignment operators. At the language level people
won't be able to use those methods. At the link level, any-
thing that would generate an implicit call to those methods
won't be able to find them.

Note that this does not mean that any class that uses a
class containing a pointer needs to define copy constructors
or assignment operators. Because the language implicitly
generates calls to copy constructors and assignment opera-
tors for any class members it will just work.

If you aren't going to provide or disable the 4
"always" methods for a class, don't define empty ones. It
doesn't do you, me, or the compiler any good, and just con-
fuses things if you try to use a tool that identifies
classes missing copy constructors and assignment operators.
Note there is one place you may want to have empty construc-
tors. That is to expose a default constructor through
inheritance. For example, an intermediate class that imple-
ments a virtual function but that is not used itself. For
example you make a shim class B that inherits from class A.
You may need to copy all the A constructors to B to keep
them exposed so that a B can act like an A.

Remember that if you have any non-class member vari-
ables that you need to have at least a default constructor
to initialize those variables.

A::A(const A &) {} IS NOT A COPY CONSTRUCTOR. It does
nothing at all.


Other Things

C++ classes have colon, ":" initializers. These should
be used instead of assignments in the body of the construc-
tor methods. Why? Well, the compiler can help you out to
find member variables that are not initialized, or that
might be initialized in an unexpected order. It is the only
way to initialize const members. By using the proper con-
structors for the member variable classes in the first
place, you reduce execution overhead. Only the proper con-
structor has to run, not the default constructor and then
whatever assignment operator is needed.

The colon initializers should appear in the order that
member variables are declared. That is the order in which
C++ initializes member variables, and good compilers will
give warnings if you try doing it in any other order, since
the will reorder the initializations to follow what the
standard says.

o Don't provide an initializer for a member that you
aren't going to provide a value for.

o DO provide an initial value for any C members. These
are the basic c/c++ non-class types such as pointers,
integers, floats, bools, etc.

o The colon initializer should be in the first column,
followed by a space and the name(value) initializer for
the first member, in order, to be initialized. If
there are more initializers, follow the initializer
with a comma, and then start a new line, beginning with
two spaces for the next initializers.

A::A(int i, double d)
: my_integer_value(i),
my_real_value(d)
{
}

o If you define any virtual methods in a class, you must define a virtual destructor. If the top-level class where the virtual class starts at doesn't have anything to destruct, you must provide a null default destructor for it.
class A {
virtual ~A() { }
};

o In most cases the copy constructor should initialize all its members to a known "null" state, and then use the assignment operator for the class to do the actual assignment. That guarantees that copy constructors and
assignment operators are identical ... which they
should be. There are some cases which might require
seperate implementations, but there should be no sur-
prises if someone switches from using a declaration and
an assignment to just using a copy constructor.

o If a class inherits from another class, remember that
you need to run the copy constructor or assignment
operator for the inherited-from classes as appropriate.
class B : A {
int _i2;
};
B::B(const B &r)
: A((const A &)r),
_i2(r._i2)
{
}
const B &B::operator=(const B &r)
{
*(A *)this = (const A &) r;
_i2 = r._i2;
return *this;
}


Your Mission, Should You Choose to Accept It

Is to go through your portions of the Niagara code
base. Identify classes that exhibit the above problems and
omissions and fix them. If you find something you can't
fix, make a note of it for later in the source code as well
as to other people. That way another person won't stumble
across the problem and wonder about what is going on. They
will find the comment and know, or perhaps know much earlier
in the game from the note.

No comments: