- 作者: 雪山肥鱼
- 时间: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
编译期间就已经确定。类型。
所以这种奇异的 继承方式,即 静态的多态。
使用实际:
因为没有虚函数模板。所以如果你想模板类的统一用的函数为虚函数(不存在) 或者 静态函数模板。则可以用此方式。
网友评论