OO Design Reference

1 Design Guidelines

1.1 Hightest Level

  • Separate conderns (SRP)
  • Design for Readability
  • Design for Change and Extension (OCP, DRY)
  • Design for Testability

Design pattern principles

  • SRP(Single-Responsibility Principle)
  • OCP(Open-Closed Principle: Open for extension and closed for modification)
  • DRY(Don’t Repeat Yourself)
  • LSP(Liskov Substitution Principle)
  • DIP(Dependence Inversion Principle): abstraction should not rely on details, detailes should rely on abstraction

1.2 Concrete Level

  • Be careful when using inheritance
  • Resist the urge to put everything into one class. Seperate concerns

    Inheritance is rarely the answer. Delegate to Services: Has-A Trumps Is-A” ——(Andrew Hunt, David Thomas, The Progmatic Programmer)

2 Implementation Guidelines

2.1 basic guidelines

  • By default, declare single-argument constructors explicit
  • Consider the alignment of data members when adding member data to a struct or class.
  • Define and initialize memver variables in the order of member declaration.
  • By default, make member functions const (Remember: Const correctness is part of the semantics of your class)
  • Don’t make data members const or references (Remember: A class with const or reference data member cannot be copy/move assigned by default)
    Eample: suppose you have the following class, it declares no copy operations, no move operations and no destructor, compiler will automatically generate these functionos if they are used
    1
    2
    3
    4
    5
    6
    7
    class StringTable {
    public:
    StringTable() {}
    ... // functions for insertion, erasure, loookup, etc. but no copy/move/dtor functionality
    private:
    std::map<int, std::string> values;
    }
    But sometime later, it’s decided that logging the default ctor and dtorof such objects would be useful
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class StringTable {
    public:
    StringTable() {
    makeLogEntry("Creating StringTable object");
    }
    ~StringTable() {
    makeLogEntry("Deleting StringTable object");
    }
    private:
    std::map<int, std::string> values;
    }
    The above implementation would make code “moving” StringTable object actually copies them, which would introduce significant performance problem. But if we use = default, this problem can be avoided.

2.2 special member function guidelines

  • The two copy operations are independent: declaring one does not prevent compilers from generating the other
  • The two move operations are not independent. If you declare either,, that prevents compilers from generating the other
  • If compiler s are willing to generate the desired special function and the generated one would behave as you want, you may choose to adopt a policy of declaring it yourself and using = default for their definiton. [good habit, make code more readable and avoid potential side effect]

2.2.1 Overall guidelines

The Rule of 0

  • If you can avoid defining default operations, do. Classes that don’t require an explicit destructor, copy constructor and copy assignment are much easier to handle.
  • Try to reduce the use of pointers, since for a class with raw pointer, more consideration should be paied for destructor / copy ctor / copy assignment / move ctor and move assignment.
  • If raw pointer is replaced with unique_ptr, we do not have to consider move ctor and move assignemnt, but we still have to pay attention to copy ctor and copy assignment

The Rule of 3

  • When you require a destructor, you most probably also require a copy constructor and copy assignment operator [e.g. class with unique_ptr instead of raw ptr]
  • If you want to copy instead of move, follow the rule of 3.

The Rule of 5

  • When you require a destructor, you most probably also require the two copy operations and the two move operations [e.g. class with raw ptr]
  • Since C++11, the rule of 5 may be more practical than the rule of 3, but in some situations, the rule of 3 still works

2.2.2 constructor

Condition for compiler to generate a default constructor
qyqvbU
Default constructor’s initialization behavior
Y97Ymdan9hCo
hmY9Hp
9GYcMN

2.2.3 destructor

o2MdFh

2.2.4 copy ctor and copy assignment

Conditions for compiler to generate default copy operations
noidoL

  • as long as programmer did not declare these two copy operations explicitly, compiler would always generate the copy operations, just like default constructor and destructor. But there are more constraints for move operations.
  • If no copy operation is explicitly declared (first condition satisfied), but second condition or third condition failed, compiler still generate default copy operations (as long as first condition is true). However, they are (implicity) deleted 【ps: = delete means explicitly deted】
  • Declaring a move operation(construction or assignment) in a class causes compilers to disable the copy operations(both), the rationale is that if member-wise move is not the proper way to move an object, there’s no reason to expect that member-wise copy is the proper way to copy it
  • semantics of = delete: They are defined (will appear in the overload sets for function calls), but just disabled.
    bGaDHJ
    8G2T6n

2.2.5 move ctor and move assignment

Conditions for compiler to generate default move operations
rkPTtF

  • If any of the 3 conditions failed, compiler will not generate the move operations
  • interpretation of the third condition
    • If all bases/data members can be move constructed/ assigned, compiler knows how to generate default move operations
    • If some bases/data members cannot be move constructed/ assigned, but it can be copy constructed/ assigned, compiler also knows how to generate move operations (can be binded to corresponding copy operations) [more intepretation: Types that aren’t “move-enabled”(i.e., that offer no special support for move operations) will be “moved” via their copy operations]
    • If some bases/data members can neither be move constructed/ assigned, nor be copy constructed/ assigned, compiler does not know how to generate the default operations.

3 Reference

  1. CPP CON Back to basics: The Special Member Functions
  2. CPP CON Back to basics: Designing Classes
  3. Effective modern C++ Item 17

Comments

Unable to load Disqus, please make sure your network can access.