引言
最近碰到了如下的写法:
public interface TBase<T extends TBase<T,F>, F extends xxx> {
xxx
}
了解过后,发现是一个Java泛型Trick1,并且在C++中也有术语CRTP2,简单的记录一下。
Java:泛型Trick
在唯一能找到的例子当中,该写法的好处是:允许我们能够在基类/接口中定义具体子类相关的方法。
在一般的Interface/BaseClass中,我们定义的无外乎是:
public void/int/String/BaseClass/Interface xxx(void/int/String/BaseClass/Interface ..);
举个例子,有一Fruit接口,有一Apple类实现,不用泛型的写法:
public interface Fruit {
Fruit getFruit();
};
// 另一个文件...
public class Apple implements Fruit {
@Override
public Fruit getFruit() {
return this;
}
};
用泛型的写法:
public interface Fruit<F extends Fruit<F>> {
F getFruit();
};
// 另一个文件...
public class Apple implements Fruit<Apple> {
@Override
public Apple getFruit() {
return this;
}
};
可直接返回子类/使用子类参数,有效避免了instanceof等多余操作。
C++:CRTP
奇异递归模板与该Trick有异曲同工之妙,在Wiki2上解释得非常详细,这里做个简化的解释。
基本格式:
template <class T>
class Base
{
// ...
};
class Derived : public Base<Derived>
{
// ...
};
在Wiki中,CRTP的用途十分多样,可以类比到Java进行尝试(todo)
静态多态
template <class T>
struct Base {
static void f() {
T::subf();
}
};
struct Derived : Base<Derived> {
static void subf();
};
// ...
void test(Base& base) {
base.f();
}
基类的方法f()直接调用子类的静态方法subf()
对象计数器
template <typename T>
struct Counter {
static int objects_created;
static int objects_alive;
Counter() {
++objects_created;
++objects_alive;
}
Counter(const counter&) {
++objects_created;
++objects_alive;
}
protected:
~Counter() {
--objects_alive;
}
};
template <typename T> int Counter<T>::objects_created( 0 );
template <typename T> int Counter<T>::objects_alive( 0 );
class X : Counter<X> {
};
class Y : Counter<Y> {
}
类X和类Y分别有各自不同的对象计数器,很容易理解
多态链
多态链代码过多,其作用和上述Java泛型Trick如出一辙,允许基类定义具体子类相关的方法,最终实现基类子类链式调用的效果:
base.basef().concretef();
多态复制
模板类继承接口(抽象类),通过重写接口的复制方法,实现子类的复制,可拓展到其他通用方法。
例如:
// 接口
class AbstractBase {
public:
virtual ~AbstractBase () = default;
virtual std::unique_ptr<AbstractBase> clone() const = 0;
};
// 模板基类实现AbstractBase,重写clone()方法
template <typename T>
class Base : public AbstractBase {
public:
std::unique_ptr<AbstractBase> clone() const override {
return std::make_unique<T>(static_cast<T const&>(*this));
}
protected:
// We make clear Shape class needs to be inherited
Base() = default;
Base(const Base&) = default;
};
class C1 : public Base<C1>{};
class C2 : public Base<C2>{};
只需使用
basePtr->clone();
即可任意拷贝C1、C2的实例