前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >openFoam源码中的C++

openFoam源码中的C++

作者头像
gzq大数据
发布2021-08-06 14:36:09
8860
发布2021-08-06 14:36:09
举报
文章被收录于专栏:大数据那些事大数据那些事

openFoam源码中涉及到的c++思想有很多,因为在计算流体力学中,域的创建尤为重要,我们可以在域中存储我们想要的物理变量如速度、压力等等。 首先:有一个宏观上的思维,我们用的大多数域对应的C++类是GeometricField,这个类里面包含了很多信息,但他的Base类其实是Field这个类,可以用下图来表示这个关系:

在这里插入图片描述
在这里插入图片描述

分析

当然,一切要从代码看起: 首先看Field基类,找到Filed的.C和.H头文件开始分析: 该类都是在Foam这个大的命名空间底下,下面定义了很多模板类。

代码语言:javascript
复制
template<class Type>
class Field;

//- Pre-declare related SubField type
template<class Type>
class SubField;

template<class Type>
void writeEntry(Ostream& os, const Field<Type>&);

template<class Type>
Ostream& operator<<(Ostream&, const Field<Type>&);

template<class Type>
Ostream& operator<<(Ostream&, const tmp<Field<Type>>&);
// 类的前置声明
class dictionary;

这里用到了很多模板类的语法,首先声明了两个模板类的前置声明Field以及SubField,在这里要注意的是为什么要进行前置声明:

由于某些原因不方便在头文件中直接引入另一个模板类的头文件,但声明变量是需要用到该模板类型,这时候就要用到模板类的前置声明

可以看到操作符重载的参数列表里用到了Field<Type>,这就必须进行前置声明,可能此时大家又有疑问,为什么操作符的重载也要进行前置声明呢,这是可以看到在Filed这个大的模板类里有这样一段友元函数的声明:

在这里插入图片描述
在这里插入图片描述

有这样一条规定:友元函数和运算符的前向声明:如果一个模板类里调用了友元函数(外面定义的方法可以使用该类里面的私有变量),而且这个友元函数里面的参数还用到了这个模板类,那么就得提前以模板的方式去声明这个类和函数。 这样大家就懂了头文件里前面这几行的声明的必要性。下面再看这个Filed类模板里面的一些难以理解的C++代码。

代码语言:javascript
复制
class Field:public tmp<Field<Type>>::refCount,public List<Type>

首先我们看到这里的Filed继承了List,相当于我们的Filed里面存储方式为一维数组的存储。 下面定义了一个copy函数:

代码语言:javascript
复制
 const UList<Type>& copySelf(const UList<Type>& mapF,tmp<Field<Type>>& tmapFcpy) const;

这里看到前后都有一个const:前面的const好理解说明这个指针不能被改变,最后这const用于修饰该函数,表示在函数内不能改变其对应对象的成员变量的值。 接下来的typedef是用来声明两个类型的,第一个typename的作用是给编译器强调后面跟的是一个类型。

代码语言:javascript
复制
typedef typename pTraits<Type>::cmptType cmptType;
typedef SubField<Type> subField;

下来该类又使用了一个内联函数, 为了解决一些频繁调用的小函数大量消耗栈空间(栈内存)的问题,特别的引入了 inline 修饰符,只是建议内联不代表编译器真的会执行

代码语言:javascript
复制
 inline static const Field<Type>& null()
        {
            return NullObjectRef<Field<Type>>();
        }

下来定义了一些该类的构造器,其中比较有意思的是:

代码语言:javascript
复制
explicit Field(const label);

这里explict的解释我总结如下: C++中的explicit关键字只能用于修饰只有一个参数的类构造函数, 它的作用是表明该构造函数是显示的, 而非隐式的, 跟它相对应的 另一个关键字是implicit, 意思是隐藏的,类构造函数默认情况下即声明为 implicit(隐式).explicit声明之后,外面调用该构造函数必须显式声明, 因为构造器若只有一个参数并且默认是implicit,在外面调用的时候可以直接等于…, 编译器会自动给你补全,这样很容易产生歧义 例子: A(int size){ …构造函数里面的变量 } 外面调用可以直接A = 10;但是这个10并不代表size,不伦不类 接下来,该类还使用了一些复制构造函数,这都是我们平常开发不经常使用的操作:

代码语言:javascript
复制
Field(const Field<Type>&);

        //- Copy constructor or re-use as specified.
        Field(Field<Type>&, bool reuse);

        //- Move constructor transferring the Field contents
        Field(Field<Type>&&);

        //- Copy constructor of tmp<Field>
        Field(const tmp<Field<Type>>&);

复制构造函数的解释: 如果类的设计者不写复制构造函数, 编译器就会自动生成复制构造函数。 大多数情况下,其作用是实现从源对象到目标对象逐个字节的复制, 即使得目标对象的每个成员变量都变得和源对象相等。 在.C文件中,我们也可以看见一些有意思的写法,比如说模板构造函数,成员变量的直接初始化等等:

代码语言:javascript
复制
const char* const Foam::Field<Type>::typeName("Field");
Foam::Field<Type>::Field(): List<Type>(){}

看懂了这个文件,在相应的找到DimensionedField和GeometricField就可以看出他们之间的继承和每次继承完以后新添的一些功能创造出了一个GeometricField这样包含很多信息的域类。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-08-05 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 分析
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档