[C++][Chap. 4] Designs and Declarations

[content]

Items 18: Make interfaces easy to use correctly and hard to use incorrectly

DO:
1. Consistent interface.
2. Compatible behaviors with built-in types.
3. Create new types to restrict possible operations on types.
4. Constrain object values.

Item 19: Treat class design as type design

DO: checklist for type design
1. How should objects be created and destroyed.
2. Difference between initialization and assignment.
3. What does it mean by pass-by-value.
4. What are the restrictions on legal values.
5. Does the new type fit into an inheritance graph.
6. What kind of type conversion are allowed.
7. What standard functions should be disallowed.
8. What operations and functions make sense for the type.
9. Who should have access to the member of the type.
10. Should you use template for the class.
11. Do you actually need a new type.

Item 20: Prefer pass-by-reference-to-const to pass-by-value

WHY: pass-by-reference is more efficient

WHY: Be careful of the type passed in. If a derived class object is passed-by-value to a base class, only the copy constructor for base class is called.

WHY: Be careful of the actual object being copied. Copying a STL container means copying all underlying objects, whereas copying STL iterator is not copying the underlying objects.

Item 21: Don’t try to return a reference when you must return an object.

DO: Do not return pointer / reference to local stack or heap-allocated object. This is broken code.

DO: Do not return pointer / reference to static object, if more than one value of that is needed.
1. If you only have one static object to return and need to do identity check on the object, it is going to always be the same object.
2. If you want different object to return each time, you are not able to pre-determine how many such static objects you need.

Item 22: Declare data members private

WHY: from encapsulation point of view, there are only two access levels:
1. private (provides encapsulation)
2. everything else

Items 23 Prefer non-member non-friend functions to member functions

WHY: Increase encapsulation, because there are less dependency on the private part of classes.

WHY: Increase packaging flexibility and functional extensibility, because we can easily divide functions into different header files under same namespace.

Items 24: Declare non-member functions when type conversion should apply to all parameters

DO: If the type conversion is needed for the current object (i.e. *this), declaring a member function does not work. You need a non-member function.

class Rational {
public:
  const Rational operator*(const Rational& rhs) const;
}
Rational result1 = one_half * 2;  // fine
Rational result2 = 2 * one_half;  // error!

Items 25: Consider supporting for a non-throwing swap

DO: Swap is originally introduced in STL, it is since become a mainstay of exception-safe programming and a common mechanism for coping with assignment to self issue.

Version1 (when you have a non-template class)
namespace widget_stuff {
class Widget {
public:
  void swap(Widget& other) {  // member swap function
    using std::swap;
    swap(plmpl, other.plmpl); // pointer to implementation
  }
}
}

namespace std {
// Changing content in std is not allowed, but totally specification for a template function of your own type is allowed.
template<> // totally specialized swap function
void swap<Widget>(Widget& a, Widget& b) {
  a.swap(b);
}
}
Version2 (when you have a template class):
namespace widget_stuff {
template<typename T>
class Widget {...};

// This is a new non-member swap function in widget_stuff space, not in std space.
// You are not allowed to overload functions in std space.
template<typename T>  
void swap(Widget<T>& a, Widget<T>& b) {
  a.swap(b);
}
}

namespace std {
// Still try to totally specify the swap function in std if possible.
// This is for the purpose of better usage. For example, users can write "using std::swap;"
// Name finding will help to select the best function to call: member function, non-member function, total specialized template function or default std function.
template<>
void swap<ASpecificType>(ASpecificType& a, ASpecificType& b); 
}
namespace std {
// error! illegal code.
// C++ allows partial specialization of class templates but does not allow partial specialization for function templates.
template<typename T>
void swap<Widget<T>>(Widget<T>& a, Widget<T>& b) {
  a.swap(b);
}
}

Leave a Reply

Your email address will not be published. Required fields are marked *