背景
在阅读源码时发现了下面的一种写法,这种写法确实
是第一次接触,一时间不理解这种写法的含义以及设计理念,于是便查找资料学习相关知识。
template<class T>
class Base : public T
{
......
};
最终确定这是c++实现mixin的方式,也就是Template Parameters as Base Classes,那么为什么会诞生这种较复杂的语法设计呢?其存在的意义是什么?
问题
有如下的BasePrint类用于提供打印功能:
class BasePrint
{
public :
virtual void print();
};
实际应用中我们对这个基类进行继承扩展,实现定制不同版本的打印功能,然后自己的实际类中继承对应的打印类,选用自己需要的打印版本。
class DerivePrint1 : public BasePrint
{
public :
// 这里为了方便就随便输出了,实际应用中比如这个print可以封装为带色彩输出或者格式化输出
virtual void myprint() {
cout<<"Hello World 1!"<<endl;
}
virtual void print() {
myprint();
}
};
class myClass : public DerivePrint1{
};
int main()
{
myClass my;
my.print();
}
那么如果此时又新增了另一种打印,我们的类中想要同时使用这两种打印呢?
class DerivePrint1 : public BasePrint
{
public :
virtual void myprint() {
cout<<"Hello World 1!"<<endl;
}
virtual void print() {
myprint();
}
};
class DerivePrint2 : public BasePrint
{
public :
virtual void myprint() {
cout<<"Hello World 2!"<<endl;
}
virtual void print() {
myprint();
}
};
class myClass:public DerivePrint1,public DerivePrint2{
};
int main()
{
myClass my;
// error,触发了多重继承的问题
my.print();
}
可以看到,多重继承存在引发Diamond-Problem的风险。于是C++ 引入了虚继承,但虚继承在某些场景下也是有一定弊端的,为此C++ 作者发明了Template Parameters as Base Classes,这便是C++ 中实现mixin的方式。
回到上面的问题,以mixin的方式来实现的话:
template <typename T>
class DerivePrint1 : public T
{
public :
void print() {
cout<<"Hello World 1!"<<endl;
T::print();
}
};
template <typename T>
class DerivePrint2 : public T
{
public :
void print() {
cout<<"Hello World 2!"<<endl;
T::print();
}
};
class myClass{
public:
void print(){
cout<<"myClass"<<endl;
}
};
int main()
{
myClass my1;
my1.print();
cout<<"-----------------------"<<endl;
DerivePrint1<myClass> my2;
my2.print();
cout<<"-----------------------"<<endl;
DerivePrint2<myClass> my3;
my3.print();
cout<<"-----------------------"<<endl;
DerivePrint2<DerivePrint1<myClass>> my4;
my4.print();
cout<<"-----------------------"<<endl;
DerivePrint1<DerivePrint2<myClass>> my5;
my5.print();
}
其输出结果如下:
myClass
-----------------------
Hello World 1!
myClass
-----------------------
Hello World 2!
myClass
-----------------------
Hello World 2!
Hello World 1!
myClass
-----------------------
Hello World 1!
Hello World 2!
myClass
可以看到,通过***parameterized inheritance***的方式实现mixin的设计,可以将多个独立的类综合起来,其中每个类就像是一个功能片段一样,且避免了多继承的风险,同时语义清晰,且允许线性化继承层级。
结论
mixin是一种设计思想,用于将相互独立的类的功能组合在一起,以一种安全的方式来模拟多重继承。而c++中mixin的实现通常采用Template Parameters as Base Classes的方法,既实现了多个不交叉的类的功能组合,又避免了多重继承的问题。
如要更深一层的了解mixin,了解Template Parameters as Base Classes,下方有几篇专门讲解mixin的博客:
- Mixin-Based Programming in C++
- C++ Mixins - Reuse through inheritance is good(推荐,相对清晰易懂)
- Mixin-Based Programming in C++
此外,stackoverflow上也有几个问题值得参考,相较于系统性的博客,以下几个问答更简明: