Featured image of post 奇异模板

奇异模板

奇异模板技术

引言

奇异递归模板模式(Curiously Recurring Template Pattern,简称 CRTP),也被称为奇异模板,是 C++ 中的一种模板编程技术。它允许基类使用派生类的类型信息,实现了一种编译时多态。

奇异递归模板模式

​ 奇异递归模板是一种利用模板技术实现的编译时多态,允许一个类在调用函数的时候实现不同的方法。

实现方法:

  • 基类使用模板类,模板参数代表了派生类类型
  • 函数里将基类指针(this)转为派生类指针并调用派生类的实现方法,达到对于传入的不同派生类实现不同的方法。
  • 派生类要继承基类,并将自己的类型传入到模板参数当中

代码实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 基类模板
template <typename Derived>
class Shape {
public:
    void draw() {
        std::cout << "所有类型draw的公用代码" << std::endl;		//进行复用,不用每个类型都写一份
        static_cast<Derived*>(this)->drawImpl();
    }
};

// 派生类:Circle
class Circle : public Shape<Circle> {
public:
    void drawImpl() {
        std::cout << "Drawing a circle." << std::endl;
    }
};

// 派生类:Square
class Square : public Shape<Square> {
public:
    void drawImpl() {
        std::cout << "Drawing a square." << std::endl;
    }
};

int main() {
    Circle circle;
    Square square;

    circle.draw();
    square.draw();
}

奇异模板特性

特点

  • 动态多态实现

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    
    class Shape {
    public:
        void draw() {
            std::cout << "所有类型draw的公用代码" << std::endl;
            drawImp();
        }
        virtual void drawImp() = 0;
    };
    
    class Circle : public Shape {
    public:
        void drawImp() {
            std::cout << "Drawing a circle." << std::endl;
        }
    };
    
    class Square : public Shape {
    public:
        void drawImp() {
            std::cout << "Drawing a square." << std::endl;
        }
    };
    
    int main() {
        Shape* circle = new Circle;
        Shape* square = new Square;
    
        circle->draw();
        square->draw();
    }
    
  • 奇异模板相较于动态多态,它在编译时确定,避免了运行时虚函数表的查询。

  • 不需要虚函数表,内存占用较小

通过函数调用实现多态

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
template <typename Derived>
class Shape {
public:
    void draw() {
        std::cout << "shared draw" << std::endl;
        static_cast<Derived*>(this)->drawImpl();
    }
};

// 派生类:Circle
class Circle : public Shape<Circle> {
public:
    void drawImpl() {
        std::cout << "Drawing a circle." << std::endl;
    }
};

// 派生类:Square
class Square : public Shape<Square> {
public:
    void drawImpl() {
        std::cout << "Drawing a square." << std::endl;
    }
};

template<typename Shape>
void Draw(Shape& shape) {
    shape.draw();
}

int main() {
    Circle circle;
    Square square;

    Draw(circle);
    Draw(square);
}
  • 其对应的动态多态形式
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Shape {
public:
    void draw() {
        std::cout << "所有类型draw的公用代码" << std::endl;
        drawImp();
    }
    virtual void drawImp() = 0;
};

class Circle : public Shape {
public:
    void drawImp() {
        std::cout << "Drawing a circle." << std::endl;
    }
};

class Square : public Shape {
public:
    void drawImp() {
        std::cout << "Drawing a square." << std::endl;
    }
};

void Draw(Shape* shape) {
    shape->draw();
}

int main() {
    Shape* circle = new Circle;
    Shape* square = new Square;

    Draw(circle);
    Draw(square);
}