Skip to content

Commit

Permalink
添加已有文件
Browse files Browse the repository at this point in the history
  • Loading branch information
du2693742095 committed Feb 27, 2023
1 parent 76b1b04 commit 25271d0
Show file tree
Hide file tree
Showing 85 changed files with 2,053 additions and 0 deletions.
959 changes: 959 additions & 0 deletions CFD/CGNS学习笔记.md

Large diffs are not rendered by default.

Binary file added CFD/CGNS树状结构.xmind
Binary file not shown.
118 changes: 118 additions & 0 deletions Programming/C&C++/设计模式/CRTP模板编程.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
## CRTP模板编程(模板注入)

### 概念

**CRTP**`Curiously Recurring Template Pattern`的缩写,中文译为**奇异的递归模板模式**, 是派生类将自己作为模板参数传递给基类, 达到模板注入的效. 其优点是可以节约动态多态查找虚函数表的时间, 在编译阶段就实现静态多态. 定义方式类似于

```c++
template <class T>
class Base
{
// methods within Base can use template to access members of Derived
};
class Derived : public Base<Derived>
{
// ...
};
```
###### 特点
- 继承自模板类
- 派生类将自身作为参数传给模板类
- 不用虚函数, **实质上是派生类重写同名函数时, 对基类函数的屏蔽**
###### 颠倒继承
对于CRTP,是在**基类中调用派生类**的成员函数。而对于virtual虚函数,则是**派生类中调用基类**的成员函数,这就是我们所说的`颠倒继承`.
### 实例
```c++
template <typename T>
class Base {
public:
void interface() {
static_cast<T*>(this)->imp();
};
};
class Derived : public Base<Derived> {
public:
void imp() {
std::cout<< "in Derived::imp" << std::endl;
}
};
int main() {
Derived b;
d.interface();
return 0;
}
```

1. 这里面使用static_cast<>而不用dynamic_cast<>的原因是 dynamic_cast应用于运行时,而模板是在编译器就进行了实例化, 所以只能用static进行转换.
2. 实质上, 这里在调用d.inerface() 的时候, 调用的是Base中的inerface(), 然后再通过static_cast转换为Derived指针进行多态函数的调用, 这个转换实际上是在编译阶段就已经做好了的



### 静态多态实例

```c++
#include <iostream>

template <typename T>
class Base{
public:
void interface(){
static_cast<T*>(this)->imp();
//static_cast<>中只能使用&或*, 否则报错
T& temp = static_cast<T&>(*this);
std::cout << typeid(temp).name() << std::endl;
}

void imp(){
std::cout << "in Base::imp" << std::endl;
}
};

class Derived1 : public Base<Derived1> {
public:
void imp(){
std::cout << "in Derived1::imp" << std::endl;
}
};

class Derived2 : public Base<Derived2> {
public:
void imp(){
std::cout << "in Derived2::imp" << std::endl;
}
};

struct Derived3 : public Base<Derived3>{};

template <typename T>
void fun(T& base){
base.interface();
}

int main(){
Derived1 d1;
Derived2 d2;
Derived3 d3;

fun(d1);
fun(d2);
fun(d3);
}
```
在调用fun的时候, 首先将模板T转换为对应的派生类类型, 然后调用派生类中, 从基类继承下来的interface函数, 在通过interface中的static_cast转换为派生类指针, 从而表现出虚函数.
注意:
被递归模板模式使用的基类模板`base`中,不能使用模板参数类型T的对象,**只能使用T的指针或引用**,因为在base中,T的类型是不完整的,因为T还要继承自`base`。
218 changes: 218 additions & 0 deletions Programming/C&C++/设计模式/模板工厂.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
## 模板工厂

### 简单版本

#### 简介:

通过模板生成不同基类产品的工厂,再通过基类的产品工厂的第二个模板参数,指定具体的派生类产品,创建出来产品后返回基类的指针,在调用时通过多态来展现出不同的产品特性。

#### 优缺点:

优点:运行快,主要在编译阶段创建工厂,且抽象度高,代码可复用程度高

缺点:每次使用时都需要创建工厂,有浪费。

#### 示例

产品类

```c++
// 基类 鞋子
class Shoes
{
public:
virtual void Show() = 0;
virtual ~Shoes() {}
};

// 耐克鞋子
class NiKeShoes : public Shoes
{
public:
void Show()
{
std::cout << "我是耐克球鞋,我的广告语:Just do it" << std::endl;
}
};
```

模板工厂

```c++
// 抽象模板工厂类
// 模板参数:AbstractProduct_t 产品抽象类
template <class AbstractProduct_t>
class AbstractFactory
{
public:
virtual AbstractProduct_t *CreateProduct() = 0;
virtual ~AbstractFactory() {}
};

// 具体模板工厂类
// 模板参数:AbstractProduct_t 产品抽象类,ConcreteProduct_t 产品具体类
template <class AbstractProduct_t, class ConcreteProduct_t>
class ConcreteFactory : public AbstractFactory<AbstractProduct_t>
{
public:
AbstractProduct_t *CreateProduct()
{
return new ConcreteProduct_t();
}
};
```

main函数

```c++
int main()
{
// 构造耐克鞋的工厂对象
ConcreteFactory<Shoes, NiKeShoes> nikeFactory;
// 创建耐克鞋对象
Shoes *pNiKeShoes = nikeFactory.CreateProduct();
// 打印耐克鞋广告语
pNiKeShoes->Show();

// 释放资源
delete pNiKeShoes;
pNiKeShoes = NULL;

return 0;
}
```



### 模板类+单例类工厂

#### 简介:

解决简单版本不能随时统一获取指定产品的缺点,增加一个单例工厂,用map保存所有的实例产品。

- 把产品注册的功能封装成产品注册模板类Register。注册的产品对象保存在工厂模板类Factory的**std::map**中,便于产品对象的获取。
- 把获取产品对象的功能封装成工厂模板类。为了能随时随地获取指定产品对象,则把工厂设计成单例模式。

#### 优缺点:

优点:运行快,实例化创建都是在编译阶段进行的,且抽象度高,复用程度好,做到了开闭原则,且扩展性和封装程度都很好。

缺点:容易让人读不懂,代码复杂。

#### 示例

产品类不变

产品注册类Register和单例工厂

```c++
// 基类,产品注册模板接口类
// 模板参数 ProductType_t 表示的类是产品抽象类
template <class ProductType_t>
class IProductRegistrar
{
public:
// 获取产品对象的抽象接口
virtual ProductType_t *CreateProduct() = 0;

protected:
// 禁止外部构造和虚构, 子类的"内部"的其他函数可以调用
IProductRegistrar() {}
virtual ~IProductRegistrar() {}

private:
// 禁止外部拷贝和赋值操作,否则容易造成悬空指针或者内存泄漏
IProductRegistrar(const IProductRegistrar &);
const IProductRegistrar &operator=(const IProductRegistrar &);
};

// 工厂模板类,用于获取和注册产品对象
// 模板参数 ProductType_t 表示的类是产品抽象类
template <class ProductType_t>
class ProductFactory
{
typedef IProductRegistrar<ProductType_t> RegisteryBase;

public:
// 获取工厂单例,特定工厂的实例是唯一的
static ProductFactory<ProductType_t> &Instance()
{
static ProductFactory<ProductType_t> instance;
return instance;
}

// 产品注册
void RegisterProduct(RegisteryBase *registrar, std::string name)
{
m_ProductRegistry[name] = registrar;
}

// 根据名字name,获取对应具体的产品对象
ProductType_t *GetProduct(std::string name)
{
// 从map找到已经注册过的产品,并返回产品对象
if (m_ProductRegistry.find(name) != m_ProductRegistry.end())
{
return m_ProductRegistry[name]->CreateProduct();
}
else{
std::cout << "No product found for " << name << std::endl;
return NULL;
}
}

private:
// 禁止外部构造和虚构
ProductFactory() {}
~ProductFactory() {}

// 禁止外部拷贝和赋值操作
ProductFactory(const ProductFactory &);
const ProductFactory &operator=(const ProductFactory &);

// 保存注册过的产品,key:产品名字 , value:产品类型
std::map<std::string, RegisteryBase *> m_ProductRegistry;
};

// 产品注册模板类,用于创建具体产品和从工厂里注册产品
// 模板参数 ProductType_t 表示的类是产品抽象类(基类),ProductImpl_t 表示的类是具体产品(产品种类的子类)
template <class ProductType_t, class ProductImpl_t>
class ProductRegistrar : public IProductRegistrar<ProductType_t>
{
public:
// 构造函数,用于注册产品到工厂,只能显示调用
explicit ProductRegistrar(std::string name)
{
// 通过工厂单例把产品注册到工厂
ProductFactory<ProductType_t>::Instance().RegisterProduct(this, name);
}

// 创建具体产品对象指针
ProductType_t *CreateProduct()
{
return new ProductImpl_t();
}
};
```
main函数
```c++
int main()
{
// 注册产品种类为Shoes(基类),产品为NiKe(子类)到工厂,产品名为nike
ProductRegistrar<Shoes, NiKeShoes> nikeShoes("nike");
Shoes *pNiKeShoes = ProductFactory<Shoes>::Instance().GetProduct("nike");
pNiKeShoes->Show();
// 释放资源
if (pNiKeShoes)
{
delete pNiKeShoes;
}
return 0;
}
```

Loading

0 comments on commit 25271d0

Please sign in to comment.