• 《Effective C++》继承与面对对象设计:条款32-条款40


    条款32:确定你的public继承塑模出is-a关系

    • public继承意味着is-a。适用于base class身上的每一个函数也一定适用于derived class。

    条款33:避免遮掩继承而来的名称

    几层作用域:

    • global作用域
      • namespace作用域
        • Base class作用域
          • Drive class作用域
            • 成员函数
              • 控制块作用域

    当前作用域会遮掩上一层作用域的名称(重载的函数也会直接遮掩)

    class Base{
    public:
        void f1();
    }
    
    class Drive : public Base {
    public:
        void f1(int);  //会遮掩f1(),子类并没有继承f1()
    }
    
    Drive d;
    d.f1();  //错误
    d.f1(3); //正确
    

    可以通过using声明式(public继承)或者inline转交(public和private继承)解决这一问题

    class Base{
    public:
        void f1();
    }
    
    //using 声明式
    class Drive:public Base {
    public:
        using Base::f1;
        void f1(int);
    }
    
    //inline转交
    class Drive : private Base {
    public:
        void f1(){
            Base::f1();
        }
        void f1(int);
    }
    

    条款34:区分接口继承和实现继承

    • 纯虚函数(只提供接口)

      • 纯虚函数造成了抽象类,抽象类不可以构造实体(对象)
      • Drived class中必须给出纯虚函数的实现
      • 纯虚函数可以给出实现(类外)
    • 虚函数(提供接口和缺省实现)

      • 用于实现多态
    • 非虚函数(提供了强制实现)

      • 可以看成此类独有,且最好不要在Drived class重新定义非虚函数

    条款35:考虑virtual函数以外的其他选择

    virtual的替代方案

    • non-virtual interface(NVI)手法,以public non-virtual成员函数包裹较低访问性(privat或protected)的virtual函数
    #include <iostream>
    #include <string>
    #include <memory>
    
    using namespace std;
    
    class base {
    public:
        void show() {
            doshow();
        }
    
    private:
        virtual void doshow() const {
            cout << "base" << endl;
        }
    };
    
    
    class drive : public base {
    public:
    
    private:
        virtual void doshow() const {
            cout << "drive" << endl;
        }
    
    };
    
    int main() {
       shared_ptr<base> d = shared_ptr<base>(new drive);
       d->show();
    }
    
    • 以函数指针变量替换virtual函数
    #include <iostream>
    #include <string>
    #include <memory>
    
    using namespace std;
    
    class base {
        typedef void (*showFuc) (const base&);
    public:
        explicit base(showFuc _s) : s(_s){}
        void doshow() const {
            cout << "base" << endl;
        }
        int show() const {
            s(*this);
        }
    
    private:
        showFuc s;
    };
    
    
    void showFuc1(const base& b) {
        cout << "function 1: ";
        b.doshow();
    }
    
    void showFuc2(const base& b) {
        cout << "function 2: ";
        b.doshow();
    }
    
    int main() {
        shared_ptr<base> b1 = shared_ptr<base>(new base(showFuc1));
        shared_ptr<base> b2 = shared_ptr<base>(new base(showFuc2));
        b1->show();
        b2->show();
    }
    
    • 利用std::function成员变量替换virtual函数(可将函数写在类中)
    #include <iostream>
    #include <string>
    #include <memory>
    
    using namespace std;
    
    class base1 {
    public:
        explicit base1(function<void(const base1&)> _f) : f(_f){}
    
        void doshow() const {
            cout << "base1" << endl;
        }
    
        void show() const {
            f(*this);
        }
    
    private:
        function<void(const base1&)> f;
    };
    
    class base2 {
    public:
        void baseFuc(const base1& b) {
            b.doshow();
        }
    };
    
    int main() {
        shared_ptr<base2> b2;
        shared_ptr<base1> b1 = shared_ptr<base1>(new base1(bind(&base2::baseFuc, b2, placeholders::_1)));
        b1->show();
    }
    
    • 古典的Strategy设计模式(将virtual函数替换为另一个继承体系内的virtual函数)
    #include <iostream>
    #include <string>
    #include <memory>
    
    using namespace std;
    
    class base2;
    
    class base1 {
    public:
        base1(const shared_ptr<base2>& _b) : b(_b) {}
    
        void doshow() const;
        void show() const ;
    private:
        shared_ptr<base2> b;
    };
    
    class base2 {
    public:
        virtual void baseFuc(const base1& b) {
            b.doshow();
        }
    };
    
    void base1::doshow() const {
        cout << "base1" << endl;
    }
    
    void base1::show() const {
        b->baseFuc(*this);
    }
    
    int main() {
        shared_ptr<base2> b2 = shared_ptr<base2>(new base2());
        shared_ptr<base1> b1 = shared_ptr<base1>(new base1(b2));
        b1->show();
    }
    

    条款36:绝不重新定义继承而来的non-virtual函数

    条款37:绝不要重新定义继承而来的缺省参数值

    • 缺省参数值是静态绑定
    • 虚函数是动态绑定
    class Base{ 
    public:
        virtual void print(int a = 1) {cout <<"Base "<< a <<endl;};
        int a;
    };
    
    class Drive : public Base{
    public:
        void print(int a = 2){cout << "Drive " << a <<endl;}
    };                                                                                 
                                                                                       
    int main(){                                                                        
      Base *b = new Drive;                                                             
      b->print();   //   vptr[0](1)
    }
    
    //Drive 1
    

    条款38:通过复合塑模树has-a 或“根据某物实现出”

    • 复合(composition)
      • has-a(应用域对象间复合)
        • 应用域(程序中塑造的某些事物,如人、汽车、视频画面等等)
      • is-implemented-in-terms-of(实现域对象间复合)
        • 实现域(实现细节的人工制品,如缓冲区、互斥器、查找树等等)

    条款39:明智而审慎的使用private继承

    • private继承(不继承接口,但继承实现)
      • 编译器不会自动将一个derived class对象转换为base class对象
      • base class的所有成员在derived class中都变成private属性
      • private继承可以造成empty class最优化(这对致力于"对象尺寸最小化"的程序开发者而言,可能很重要)
    class Base{
    public:
        void fun(){}
    }
    
    //8个字节
    class Object{
    private:
        int a;
        Base b;
    };
    
    //4个字节
    class Object : private Base{
    private:
        int a;
    }
    

    条款40:明智而审慎的使用多重继承

    • 多重继承可能导致歧义(菱形继承)
    class A { ... };
    class B: public A { ... };
    class C: public A { ... };
    class D: public B, public C { ... };
    //D中会包含两份A的成员变量
    
    • 采用virtual继承解决歧义
      • virtual继承会增加大小、速度、初始化及赋值等等成本
      • 如果base class不带有任何数据,virtual继承比较有实用价值
    class A { ... };
    class B: virtual public A { ... };
    class C: virtual public A { ... };
    class D: public B, public C { ... };
    //D中只包含一份A的成员变量
    
    • 有一些情况可采用 "public继承抽象class(继承接口)" 和 "private继承继承协助实现class(继承实现)" 两相结合的方法
  • 相关阅读:
    PDOStatement::closeCursor
    PDOStatement::bindValue
    oracle drop table recyclebin恢复
    mysql基准测试工具tpcc-mysql安装、使用、结果解读
    MySQL字符集 GBK、GB2312、UTF8区别 解决 MYSQL中文乱码问题 收藏 MySQL中涉及的几个字符集
    [MySQL FAQ]系列 — EXPLAIN结果中哪些信息要引起关注
    [MySQL优化案例]系列 — 优化InnoDB表BLOB列的存储效率
    数据库专业词语
    老叶观点:MySQL开发规范之我见
    [MySQL FAQ]系列 — 为什么InnoDB表要建议用自增列做主键
  • 原文地址:https://www.cnblogs.com/narjaja/p/10209196.html
Copyright © 2020-2023  润新知