美文网首页
模板中的继承关系

模板中的继承关系

作者: 404Not_Found | 来源:发表于2022-01-23 07:23 被阅读0次
    • 作者: 雪山肥鱼
    • 时间:20220104 21:54
    • 目的: 模板中的特殊的继承关系

    奇异(奇特)的递归模板模式(CRTP)

    在基类中使用派生类对象

    在模板中 继承自己,是一种模板编程手法

    class Derived1:public Base<Derived1> { }
    
    template<typename T>
    class Base {
    public:
        void asDerived() {
          T &derived = static_cast<T&>(*this);
          cout<<typeid(derived).name()<<endl;
          derived.myfunc();
        }
    }
    
    class Derived1:public Base<Derived1> {
    public:
      void myfunc() {
          cout<<"Derived1::myfunc() is called"<<endl;
      }
    }
    
    template<typname T>
    class Derived2:public Base<Derived2<T>> {
    
    }
    
    int main() {
      Derived1 myd;
      myd.asDerived();
      
      return 0;
    }
    

    因为单继承,static_cast<T&>(*this) 合理,基类对象和派生类对象共用一块内存。

    防笔误技巧

    //也可以调用到 
    //cout << "Derived1::myfunc() is called" << endl;
    class Derived3 :public Base<Derived1> {
    
    };
    int main() {
    
        Derived1 myd;
        myd.asDerived();
    
        Derived3 myd3;
        myd3.asDerived();
    
        return 0;
    }
    

    但结果是:

    图片.png

    改进:引入友元

    template<typename T>
    class Base {
    public:
        void asDerived()
        {
            T &derived = static_cast<T&>(*this);
            cout << typeid(derived).name() << endl;
            derived.myfunc();
        }
    
    private:
        Base() {};
        friend T;// T 派生类 友元类
    
    };
    
    class Derived1 :public Base<Derived1> {
    public:
        void myfunc() {
            cout << "Derived1::myfunc() is called" << endl;
        }
    };
    
    template<typename T>
    class Derived2 :public Base<Derived2<T>> {
    
    };
    
    /*
    //笔误也可以掉到 
    //cout << "Derived1::myfunc() is called" << endl;
    class Derived3 :public Base<Derived1> {
    
    };
    */
    /*防止写错*/
    //class Derived3 :public Base<Derived1> {
    //deirved3 传到了 base中 是 Base的友元,所以 Derived3 可以访问 base的私有函数,改成deirved1,则无法derived1 是 base 友元,与derived3 没关系了
    class Derived3 :public Base<Derived3> {
    public:
        void myfunc() {
            cout << "Derived3::myfunc() is called" << endl;
        }
    };
    
    int main() {
    
        Derived1 myd;
        myd.asDerived();
    
        Derived3 myd3;
        myd3.asDerived();
    
        return 0;
    }
    

    核心技巧如备注所说:
    deirved3 传到了 base中 是 Base的友元,所以 Derived3 可以访问 base的私有函数,改成deirved1,则无法derived1 是 base 友元,与derived3 没关系了。

    基于减少派生类中代码量的考虑

    出发点:尽可能把代码转移到基类中,减少派生类的代码。

    template<typename T>
    struct shap {
        //把派生类对象是否相等的判断移动到了 基类中
        //重点: 使用了在类模板中定义友元函数的手段把全局 operator== 放到基类中。
        //如果是成员函数: 则只有一个形参 bool operator==(const shap<T> & obj1)
        //用friedn 修饰了 说明operator== 是一个全局函数
        friend bool operator==(const shap<T> &obj1, const shap<T> & obj2) {
            const T&objtmp1 = static_cast<const T &>(obj1);
            const T&objtmp2 = static_cast<const T &>(obj2);
            if (!(objtmp1 < objtmp2) && !(objtmp1 < objtmp2)) {
                return true;
            }
            return false;
        }
    
    };
    
    struct square :public shap<square> {
        int sidelength;
    };
    
    bool operator<(square const & obj1, square const & obj2) {
        if (obj1.sidelength < obj2.sidelength) {
            return true;  
        }
    }
    
    int main() {
        square objsq1;
        objsq1.sidelength = 15;
        square objsq2;
        objsq2.sidelength = 20;
        if (!(objsq2 == objsq1)) {
            cout << "not equal" << endl;
        }
        else {
            cout << "equal" << endl;
        }
    
    }
    

    用friend 修饰 代表的该全局函数可以访问该类的private。

    //实现在外面:
    template<typename T>
    bool operator==(const shape<T>& obj1, const shape<T>& obj2) {
      const T & objtmp1 = static_cast<const T&>(obj1);
      const T & objtmp2 = static_cast<const T &>(obj2);
      ...
    }
    

    基类调用派生类的结构与多态体现

    //因为基类可以调用派生类的方法,因此有很多事情可以在基类中做
    template<typename T>
    class Human {
    public:
        T & toChild()
        {
            return static_cast<T&>(*this);
        }
        void parenteat() {
            toChild().eat();
        }
    
    private:
        Human() {};
        friend T;
    };
    
    class Men :public Human<Men> {
    public:
        void eat() {
            cout << "men like noodles" << endl;
        }
    };
    
    class Women :public Human<Women> {
    public:
        void eat() {
            cout << "women like rice" << endl;
        }
    };
    
    template<typename T>
    void myrHumanFuncTest(Human<T>&tmpobj) {
        tmpobj.parenteat();
    }
    
    int main() {
        Men mymen;
        Women mywomen;
        mymen.eat();
        mywomen.eat();
    
        myrHumanFuncTest(mymen);
        myrHumanFuncTest(mywomen);
        return 0;
    }
    
    example.png

    编译期间就已经确定。类型。
    所以这种奇异的 继承方式,即 静态的多态。
    使用实际:
    因为没有虚函数模板。所以如果你想模板类的统一用的函数为虚函数(不存在) 或者 静态函数模板。则可以用此方式。

    相关文章

      网友评论

          本文标题:模板中的继承关系

          本文链接:https://www.haomeiwen.com/subject/bzhecrtx.html