C++技巧之CRTP

C++技巧之CRTP

CRTP(Curiously Recurring Template Pattern),一种C++编程技巧技巧,其将派生类作为模板传递给基类,能够实现静态多态等功能

/**
 * 基类
**/
templace<typename T>
class Base {
    ...
};

/**
 * 派生类
**/
class Derived : public Base<Derived> {
    ...
};

实现静态多态

使用static_cast而不需要使用虚函数实现多态

/**
 * 基类
**/
templace<typename T>
class Base {
    void interface() {
        static_cast<T*>(this)->implementation();
    }
};

/**
 * 派生类
**/
class Derived : public Base<Derived> {
    void implementation();
};

统计类对象的存活对象数目

templace<typename T>
class Base {
public:
    Base() {
        count++;
    }
    
    ~Base() {
        count--;
    }

    getCountAlive() {
        return count;
    }

private:
    static int count;
}

/**
 * 派生类
**/
class Derived : public Base<Derived> {
    ...
};

在上面的代码中,实现了基类和派生类存活对象数目的分别计数,分别调用基类和派生类对象的getCountAlive()可分别得到基类和派生了的存活数目,避免了各个基类和派生类中的用于计数的冗余代码

多态链

class Printer {
public:
    Printer(ostream& pstream) : m_stream(pstream) {
        ...
    }
 
    template <typename T>
    Printer& print(T&& t) { 
        m_stream << t;
         return *this;
    }
 
    template <typename T>
    Printer& println(T&& t) { 
        m_stream << t << endl;
         return *this;
    }
private:
    ostream& m_stream;
};

class CoutPrinter : public Printer {
public:
    CoutPrinter() : Printer(cout) {
        ...
    }

    CoutPrinter& SetConsoleColor(Color c) {
        // ...
        return *this;
    }
};

CoutPrinter().print("Hello ").SetConsoleColor(Color.red).println("Printer!"); // 报错

在最后一行使用时,CoutPrinter().print("Hello ")返回的时Printer实例,而后边的SetConsoleColor(Color.red)调用的是CoutPrinter实例,造成编译器报错

使用CRTP则可以解决该问题

template <typename ConcretePrinter>
class Printer {
public:
    Printer(ostream& pstream) : m_stream(pstream) {}
 
    template <typename T>
    ConcretePrinter& print(T&& t) {
        m_stream << t;
        return static_cast<ConcretePrinter&>(*this);
    }
 
    template <typename T>
    ConcretePrinter& println(T&& t) {
        m_stream << t << endl;
        return static_cast<ConcretePrinter&>(*this);
    }
private:
    ostream& m_stream;
};
 
class CoutPrinter : public Printer<CoutPrinter> {
public:
    CoutPrinter() : Printer(cout) {}
 
    CoutPrinter& SetConsoleColor(Color c) {
        ...
        return *this;
    }
};
 
// usage
CoutPrinter().print("Hello ").SetConsoleColor(Color.red).println("Printer!");

实现侵入式链表

定义存放节点的容器类

template <typename T>
class LinkedList {
public:
    // The "root" node is self-referential, and forms the basis of a circular
    // list (root_.Next() will point back to the start of the list,
    // and root_->Previous() wraps around to the end of the list).
    LinkedList() {}
    LinkedList(const LinkedList&) = delete;
    LinkedList& operator=(LinkedList&) = delete;
    LinkedList() {}
    LinkedList(const LinkedList&) = delete;
    LinkedList& operator=(LinkedList&) = delete;

    void append(LinkNode<T>* e) { 
        e->insertBefore(&root_); 
    }

    LinkNode<T>* head() const { 
        return root_.next(); 
    }

    LinkNode<T>* tail() const { 
        return root_.previous(); 
    }

    const LinkNode<T>* end() const { 
        return &root_;
    }

    bool empty() const { 
        return head() == end(); 
    }
private:
    LinkNode<T> root_;
};

定义节点

template <typename T>
class LinkNode {
public:
    // LinkNode are self-referential as default.
    LinkNode() : prev_(this), next_(this) {}
    LinkNode(LinkNode<T>* prev, LinkNode<T>* next) : prev_(prev), next_(next) {}
    LinkNode(const LinkNode&) = delete;
    LinkNode& operator=(const LinkNode&) = delete;

    void insertBefore(LinkNode<T>* e) {
        e->next_ = this;
        this->prev_ = e;
    }

    void insertAfter(LinkNode<T>* e) {
        e->prev_ = this;
        this->next_ = e;
    }

    void removeFromList() {
        prev_->next_ = next_;
        next_->prev = prev_;
    }

    LinkNode<T>* previous() const { 
        return prev_; 
    }
    LinkNode<T>* next() const { 
        return next_; 
    }

    const T* value() const { 
        return static_cast<const T*>(this); 
    }
    T* value() { 
        return static_cast<T*>(this);
    }

private:
    LinkNode<T>* prev_;
    LinkNode<T>* next_;
};

派生类,使用CRTP

class MyNodeType : public LinkNode<MyNoeType> {
  ...
};

使用:

LinkedList<MyNodeType> list;
LinkNode<MyNodeType>* n1 = ...;
LinkNode<MyNodeType>* n2 = ...;
LinkNode<MyNodeType>* n3 = ...;
list.Append(n1);
list.Append(n3);
n2->InsertBefore(n3);
for (LinkNode<MyNodeType>* node = list.head();
   node != list.End();
   node = node->Next()) {
  MyNodeType* value = node->value();
  ...
}

参考
c++ 中CRTP的用途
C++编程技巧:CRTP

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值