Thursday, August 30, 2007

Effective C++ (4-7)

item 4: Make sure that objects are initialized before they're used
  • Different between assignment and initialization.
  • Using "member initialization list". Must be used: data members are const or are references.
    The assignment-based version first called default constructors to initialize theName, theAddress, and thePhones, then promptly assigned new values on top of the default-constructed ones. All the work performed in those default constructions was therefore wasted. The member initialization list approach avoids that problem, because the arguments in the initialization list are used as constructor arguments for the various data members. In this case, theName is copy-constructed from name, theAddress is copy-constructed from address, and thePhones is copy-constructed from phones. For most types, a single call to a copy constructor is more efficient — sometimes much more efficient — than a call to the default constructor followed by a call to the copy assignment operator.
  • The last example shows the order of initialization.
item 5: Know what functions C++ silently writes and calls
  • What does an empty class include
    class Empty{};

    it's essentially the same as if you'd written this:

    class Empty {

    public:

    Empty() { ... } // default constructor

    Empty(const Empty& rhs) { ... } // copy constructor



    ~Empty() { ... } // destructor — see below

    // for whether it's virtual



    Empty& operator=(const Empty& rhs) { ... } // copy assignment operator

    };

    These functions are generated only if they are needed, but it doesn't take much to need them. The following code will cause each function to be generated:

    Empty e1;                               // default constructor;

    // destructor



    Empty e2(e1); // copy constructor



    e2 = e1; // copy assignment operator
  • When need to write the copy assignment operator by yourself.
    If you want to support assignment in a class containing a reference member, you must define the copy assignment operator yourself

item 6: Explicitly disallow the use of compiler-generated functions you do not want
  • Sometimes you don't want to use the copy constructor or copy assignment operator: HomeForSale h1; HomeForSale h2; -- You don't want the following happen:
    HomeForSale h3(h1); h1 = h2;
  • Solution: declare the corresponding member functions private and give no implementations.
class Uncopyable{
protected:
Uncopyable(){}
~Uncopyable(){}

private:
Uncopyable(const Uncopyable&);
Uncopyable& operator=(const Uncopyable&);
};


To keep HomeForSale objects from being copied, all we have to do is inherit from Uncopyable:
class HomeForSale:private Uncopyable{
...
}
The compiler-generated versions of these functions will try to call their base class counterparts, and those calls are rejected, because the copying operations are private in the base class.

item 7:
Declare destructors virtual in polymorphic base classes
  • C++ specifies that when a derived class object is deleted through a pointer to a base class with a non-virtual destructor, results are undefined. So give the base class a virtual destructor.
  • Any class with virtual functions should almost certainly have a virtual destructor.
  • If a class does not contain virtual functions, that often indicates it is not meant to be used as a base class. When a class is not intended to be a base class, making the destructor virtual is usually a bad idea. (check the example why)
  • You want abstract class but don't have any pure virtual functions. Use a pure virtual destructor.
  • At the end, the way destructors work.

No comments:

Post a Comment