# C++：使用 CRTP 模式实现静态多态

## 经典例子：形状的面积计算

### 定义基类

`````` 1#include <iostream>
2#include <cmath>
3
4template <typename Derived>
5class Shape {
6public:
7    void area() {
8        static_cast<Derived*>(this)->computeArea();
9    }
10};
``````

### 定义派生类

`````` 1class Circle : public Shape<Circle> {
2public:
4
5    void computeArea() {
7        std::cout << "Circle area: " << area << std::endl;
8    }
9
10private:
12};
13
14class Rectangle : public Shape<Rectangle> {
15public:
16    Rectangle(double width, double height) : width(width), height(height) {}
17
18    void computeArea() {
19        double area = width * height;
20        std::cout << "Rectangle area: " << area << std::endl;
21    }
22
23private:
24    double width, height;
25};
``````

### 使用 CRTP

``````1int main() {
2    Circle circle(5.0);
3    circle.area();  // 输出：Circle area: 78.5398
4
5    Rectangle rectangle(4.0, 6.0);
6    rectangle.area();  // 输出：Rectangle area: 24
7
8    return 0;
9}
``````

## 对比虚函数多态的方式

`````` 1#include <iostream>
2#include <cmath>
3
4class Shape {
5public:
6    virtual void computeArea() const = 0;  // 纯虚函数
7    virtual ~Shape() = default;  // 虚析构函数
8};
9
10class Circle : public Shape {
11public:
13
14    void computeArea() const override {
16        std::cout << "Circle area: " << area << std::endl;
17    }
18
19private:
21};
22
23class Rectangle : public Shape {
24public:
25    Rectangle(double width, double height) : width(width), height(height) {}
26
27    void computeArea() const override {
28        double area = width * height;
29        std::cout << "Rectangle area: " << area << std::endl;
30    }
31
32private:
33    double width, height;
34};
35
36int main() {
37    Shape* circle = new Circle(5.0);
38    circle->computeArea();  // 输出：Circle area: 78.5398
39
40    Shape* rectangle = new Rectangle(4.0, 6.0);
41    rectangle->computeArea();  // 输出：Rectangle area: 24
42
43    delete circle;
44    delete rectangle;
45
46    return 0;
47}
``````

## 对比模板（无继承）的方式

`````` 1#include <iostream>
2#include <cmath>
3
4class Circle {
5public:
6    Circle(double r) : radius(r) {}
7
8    double getArea() const {
10    }
11
12private:
14};
15
16class Rectangle {
17public:
18    Rectangle(double l, double w) : length(l), width(w) {}
19
20    double getArea() const {
21        return length * width;
22    }
23
24private:
25    double length;
26    double width;
27};
28
29template <typename Shape>
30double calculateArea(const Shape& shape) {
31    return shape.getArea();
32}
33
34int main() {
35    Circle circle(5.0);
36    Rectangle rectangle(10.0, 4.0);
37
38    std::cout << "Circle area: " << calculateArea(circle) << std::endl;
39    std::cout << "Rectangle area: " << calculateArea(rectangle) << std::endl;
40
41    return 0;
42}
``````

## 对比 Rust 的 Enum 静态多态

`````` 1use std::f64::consts::PI;
2
3enum Shape {
4    Circle(f64),
5    Rectangle(f64, f64),
6}
7
8impl Shape {
9    fn area(&self) -> f64 {
10        match self {
12            Shape::Rectangle(length, width) => length * width,
13        }
14    }
15}
16
17fn main() {
18    let circle = Shape::Circle(5.0);
19    let rectangle = Shape::Rectangle(10.0, 4.0);
20
21    println!("Circle area: {}", circle.area());
22    println!("Rectangle area: {}", rectangle.area());
23}
``````

## 头脑风暴：C++ 能不能也搞个枚举多态？

C++中，虽然没有直接与Rust的枚举完全等价的机制，但可以通过使用联合和结构体来实现类似的静态多态。

`````` 1#include <iostream>
2#include <cmath>
3
4enum class ShapeType {
5    Circle,
6    Rectangle
7};
8
9union ShapeData {
11    struct {
12        double length;
13        double width;
14    } rectangle; // 用于Rectangle
15
16    ShapeData() {} // 默认构造函数
17    ~ShapeData() {} // 析构函数
18};
19
20struct Shape {
21    ShapeType type;
22    ShapeData data;
23
25        type = ShapeType::Circle;
27    }
28
29    Shape(double length, double width) {
30        type = ShapeType::Rectangle;
31        data.rectangle.length = length;
32        data.rectangle.width = width;
33    }
34
35    double area() const {
36        switch (type) {
37            case ShapeType::Circle:
39            case ShapeType::Rectangle:
40                return data.rectangle.length * data.rectangle.width;
41            default:
42                throw std::runtime_error("Unknown shape type");
43        }
44    }
45};
46
47int main() {
48    Shape circle(5.0);
49    Shape rectangle(10.0, 4.0);
50
51    std::cout << "Circle area: " << circle.area() << std::endl;
52    std::cout << "Rectangle area: " << rectangle.area() << std::endl;
53    return 0;
54}
``````