1. 有的情况下,现在的折衷方案比未来的理想方案好得多

  2. 我考虑问题的本质是什么,再定义一个类抓住这个本质,并确保这个类能独立地工作。然后在遇到符合这个本质的问题时就使用这个类。

  3. 只要类定义正确,我就只能按照我编写它的初衷那样去用它。

  4. C++ 哲学:抽象,实用,只为用到的东西付出代价。

  5. 类设计者的核查表:

    • 你的类需要一个构造函数吗?
    • 你的数据成员是私有的吗?(使用函数,可以延迟计算,不必时时计算,保证数据成员的准确性)
    • 你的类需要一个无参的构造函数吗?(对象数组)
    • 是不是每个构造函数初始化所有的数据成员?
    • 类需要析构函数吗?
    • 类需要一个虚析构函数吗?
    • 你的类需要复制构造函数吗?(是否需要深拷贝)
    • 你的类需要一个赋值操作符吗?
    • 你的赋值操作符能正确地将对象赋给对象本身吗?
    • 你的类需要定义关系操作符吗?
    • 删除数组时你记住了用 delete[] 吗?
    • 记得在复制构造函数和赋值操作符的参数类型中加上 const 了吗?
    • 如果函数有引用参数,它们应该是 const 引用吗?
    • 记得适当地声明成员函数为 const 的了吗?
  6. 代理类:用类来表示概念(RAII

    class Vehicle{
    public:
        virtual double weight() = 0;
        virtual void start() = 0;
        virtual Vehicle* copy() const = 0;
        virtual ~Vehicle(){}
    };
    class RoadVehicle: public Vehicle{
        /* ... */
    };
    class AutoVehicle: public RoadVehicle{
        /* ... */
    };
    class Aircraft: public Vehicle{
        /* ... */
    };
    class Helicopter: public Aircraft{
        /* ... */
    };
    
    // 定义代理类
    class VehicleSurrogate{
    public:
        VehicleSurrogate(){     // 空代理
            vp(0);
        }
        VehicleSurrogate(const Vehicle& v){
            vp = v.copy();
        }
        ~VehicleSurrogate(){
            delete vp;
        }
        VehicleSurrogate(const VehicleSurrogate& v){
            vp(v.vp ? v.vp->copy() : 0);
        }
        VehicleSurrogate& operator=(const VehicleSurrogate&){
            if(this != &v){
                delete vp;
                vp = (v.vp ? v.vp->copy() : 0);
            }
            return *this;
        }
        /*
        其实代理类也可以不依依写出 Vehicle 所能支持的其他操作
        只需要实现 * 和 -> 的操作符重载即可,做一次转发,
        但这样就过多地暴露了内存分配方面的策略,不太安全
        */
        double weight() const{
            if(vp == 0){
                throw "empty VehicleSurrogate.weight()";
            }
            return vp->weight();
        }
        void start() {
            if(vp == 0){
                throw "empty VehicleSurrogate.start()";
            }
            return vp->start();
        }
    private:
        Vehicle* vp;
    };
    int main(){
        // Vehicle parking_lot[1000];  // wrong
        VehicleSurrogate parking_lot[1000];  // OK
        AutoVehicle x;
        parking_lot[num_vehicles++] = x;
        return 0;
    }
    
  7. Handle 句柄类:就是一种只包含单个对象的容器 与智能指针的理念类似,智能指针更像是 Handle 类的抽象

    class Point{
    public:
        Point(int x = 0, int y = 0):xval(x), yval(y){
            cout << "Point()" << endl;
        }
        Point(const Point& p){
            cout << "Point(const Point& p)" << endl;
            xval = p.xval;
            yval = p.yval;
        }
        ~Point(){
            cout << "~Point()" << endl;
        }
        int x() const {return xval;}
        int y() const {return yval;}
        Point& x(int xv){
            xval = xv;
            return *this;
        }
        Point& y(int yv){
            yval = yv;
            return *this;
        }
        void print(){
            cout << "x: " << xval << " y: " << yval << endl;
        }
    private:
        int xval, yval;
    };
    
    class Handle;
    
    class UPoint{
        friend class Handle;
        Point p;
        int u;
    
        UPoint():u(1){}
        UPoint(int x, int y):p(x, y), u(1){}
        UPoint(const Point& p0):p(p0), u(1){}
    };
    
    class Handle{
    public:
        Handle():up(new UPoint){}
        Handle(int x, int y):up(new UPoint(x, y)){}
        Handle(const Point &p):up(new UPoint(p)){}
        Handle(const Handle &h):up(h.up){++up->u;}
        ~Handle(){
            if(--up->u == 0){
                delete up;
            }
        }
        Handle& operator=(const Handle& h){
            ++h.up->u;
            if(--up->u == 0){
                delete up;
            }
            up = h.up;
            cout << up->u << endl;
            return *this;
        }
        int x() const{
            return up->p.x();
        }
        int y() const{
            return up->p.y();
        }
        /*指针语义
        不必复制 UPoint 对象
        Handle& x(int x){
            up->p.x(x);
            return *this;
        }
        Handle& y(int y){
            up->p.y(y);
            return *this;
        }
        */
    
        /*值语义
        写时复制
        */
        Handle& x(int x){
            copyWhenWrite();
            up->p.x(x);
            return *this;
        }
        Handle& y(int y){
            copyWhenWrite();
            up->p.y(y);
            return *this;
        }
    private:
        void copyWhenWrite(){
            if(up->u != 1){
                --up->u;
                up = new UPoint(up->p);
            }
        }
    private:
        UPoint * up;
    };
    
    int main()
    {
        Point p(10, 20);
        Handle hp(p);   // 通过拷贝构造创建一个p的副本,并将 handle绑定到该副本
        Handle hpp(hp);
        Handle hppp(hp);
        Handle hpppp;
        hpppp = hp;
        hpppp.x(100).y(200);
        cout << hp.x() << ", " << hp.y() << endl; 
        cout << hpppp.x() << ", " << hpppp.y() << endl; 
    
        return 0;
    }
    

    输出:

    Point()
    Point(const Point& p)
    1
    2
    3
    Point()
    ~Point()
    4
    Point(const Point& p)
    10, 20
    100, 200
    ~Point()
    ~Point()
    ~Point()
    
  8. 对象和值之间的差别只在要改变对象时才显现出来。换句话说,就是值和不可变的对象是无法区分的。