OpenFOAM 中 c++ 基礎


文件布置

在 OpenFOAM 中,所有代碼都以注釋段開頭,使用有限體積的 CFD 類型文件都包括以下頭文件

#include "fvCFD.H"

在此頭文件種,僅包含類或函數的定義,函數的內容會在運行時以動態形式調用。

fvCFD.H 文件被引用后,在對應的編譯設置文件 Make/options 中還需要添加如下命令

EXE_INC = \
			-I${LIB_SRC}/finiteVolume/lnInclude

EXE_LIBS = \
			-lfiniteVolume

這兩句話指定了在編譯時尋找頭文件的位置和需要鏈接的函數庫。

fvCFD.H 中,為了避免被多次引用,定義了如下宏變量

# ifndef fvCFD_H
# define fvCFD_H

當頭文件已經引用過后,ifndef 判斷返回 0,此時文件內直到 #endif 命令之間內容全部不會被再次引用。

fvCFD.H 中之后包含了一系列頭文件,並以如下內容結束

#ifndef namespaceFoam
#define namespaceFoam
    using namespace Foam;
#endif

此代碼定義了命令空間 Foam,在包含的庫中所有的函數聲明都屬於命令空間 Foam,因此在調用庫函數時必須使用。

在 c++ 代碼中,必須包含 main 函數的實例,並且程序執行時是從此函數開始。在 c++ 的 main 函數中,使用以下參數並返回一個整數

int main(int argc, char *argv[])

c++ 編程基礎

操作符

對於輸入和輸出可以使用標准庫 iostream

cout << "Please type an integer!" << endl;
cin >> myInteger;

其中操作符 <<>> 為輸出和輸入操作符,endl 為換行操作符。在 OpenFOAM 中推薦使用新的輸出流 info,其優點是可以在並行計算情況中使用。

變量可以相加減,相乘除,並且當自定義類型指定了轉化方法時還可以轉化為其他類型的變量。在 OpenFOAM 中一些變量還可以使用算術運算符,但並非所有都可以。

c++ 中一些運算符包括 +-*/ 等,以及其他標准運算符,例如 %++--+=-=/=%=等,用戶自定義類型應自己定義這些運算符計算過程。

標准數學函數定義在標准庫 cmath 中,因此並不是 c++ 的一部分,例如三角函數,指數函數和對數函數等。

分支

判斷語句形式為: if (variable1 > variable2) {...CODE...} else {...CODE...}
比較操作符包括:<><=>===!=
循環語句形式為:for (int; condition; change) {...CODE...}

函數

在 c++ 中,函數可能有或者沒有返回值,對於沒有參數或返回值的函數,對應位置用 void 指定。在 c++ 中允許多個函數為同一函數名,只要其參數的個數或類型不同就不會在編譯時報錯。

變量域由花括號指定 {},一個在花括號內定義的變量,僅在此區域內可見。可能有多個變量為同一個名字,但是在每個域內僅代表唯一的一個變量。為了使用全局變量,可以用 :: 操作符指明變量所在的域。

函數的調用前必須進行聲明,函數的聲明一般放在頭文件內,如 #include "file.h"#include <standardfile>。在編程時,將函數的聲明和定義放在不同的文件中是一種良好的習慣,在 OpenFOAM 中也是采用這種方式。

如果函數中某個參數需要改變變量值,那么參數的類型必須是引用,例如

vodi change(double& x1)

此時對應的變量 x1 將為參數的引用,而非函數內的局部變量。在 c++ 內對函數進行調用時,需要對輸入參數進行復制,引用也可以避免對內存占用較多的變量進行復制。為了避免對輸入參數進行錯誤的修改,也可以定義輸入參數的類型為常量型引用,即

void changeWord(const string& s)

定義函數時可以給定參數的默認值,在函數調用時可以減少此參數的值。

類型

在 c++ 中變量可以包含不同的類型,在定義時可以用 int myInteger,或用 cont int myConstantInteger = 10 來定義常數。在 c++ 中也可以自定義類型,並且在 OpenFOAM 中包含了多種自定義類型。

指針是指向內存空間的變量,指針變量可以從變量的定義看出

int *pint;
double *pdouble;
char *pchar;

可以用 typedef 來定義新的變量類型

typedef vector<int> integerVector;
integerVector iV;

這種方法可以簡化大型程序,例如 OpenFOAM 代碼的復雜度,使得代碼易讀性更好。

命名空間

當不同編程人員使用 c++ 寫程序時可能會有命名重復的風險。
通過將聲明的區域增加命名空間可以有效控制聲明的變量是否可見,例如 OpenFOAM 中常用的

using namespace Foam;

可以使所有定義在命名空間 Foam 內的聲明可見。
定義命名空間的形式為

namespace name {
	// declarations
}

此時,新的定義就加入到了命名空間內,並且在此作用域內可以使用命名空間定義的其他代碼。

面向對象

面向對象的思想是將關注點放在對象而非函數上。對象是類的實例,對於屬於同一類的對象包含有相同的屬性。面向對象的優勢在於增加了代碼的復用性,每個類可以為不同的目標進行設計和編寫。在 c++中,類與變量類型是同一個概念,所以類也可以看做是一種新的變量類型。

對象聲明

下面代碼定義了 name 類及其公有或私有的方法和數據

class name{
public:
	// public member functions and data members
private:
	// hidden member functions and data members
}

類的公有屬性(方法和數據)在類外部是可見的,而私有屬性則不可見。
對於沒有指定 public 或 private 的屬性,其默認是 private。
類中方法和數據的聲明與普通函數與變量相同。

類的使用

定義類的對象方法為

name nameObject;

一個類可以有多個對象,並且每個對象包含的屬性都是相互獨立的。可以聲明對象的指針或引用,但是其調用類包含的方法時需要用 -> 符號,例如

p1 = &nameObject; // reference
p2 = new name;    // pointer
p1->write();
p2->write();

類中方法的定義可以在類的定義里,也可以在其外部。

inline void name::write()
{
	// Contents of the member function.
}

例如上述代碼定義了 name 類中的 write() 方法。在函數定義時,name:: 指出了方法 write 屬於 name 類,而 inline 關鍵字則指出方法會在調用處進行展開,而非像普通函數那樣在內存空間中跳轉。對於直接定義在類中的方法,會自動使用 inline 關鍵字進行展開。

在類的方法中可以自由方法類的所有數據和方法,而不受任何限制。

和普通函數一樣,類的聲明和定義也應該分開,放在不同的文件內。在 OpenFOAM 中,大部分類都是使用此種模式。對於 inline 類型函數,需要將函數的定義放在對應的頭文件內。

構造函數

構造函數是類的對象在調用時使用的特定的初始化函數。當沒有使用特定的構造函數時,即使用 null 構造函數,對象的所有屬性都是未定義的。
在初始化時,根據給定的參數不同調用對應的構造函數。下面給出了 Vector 類的構造函數的幾個示例

// Constructors
	// Construct null
	inline Vector();
	// Construct given VectorSpace
	inline Vector(const VectorSpace<Vector<Cmpt>, Cmpt, 3>&);
	// Construct given three components
	inline Vector(const Cmpt& vx, const Cmpt& vy, const Cmpt& vz);
	// Construct from Istream
	inline Vector(Istream&;)

析構函數

當對內存空間申請后,在類的析構函數中必須對內存進行釋放。為保證所有內容都得到釋放,最好顯式的對析構函數進行定義。
在析構函數中不需要任何參數,並且函數名與類名相同,但是函數名前增加了 ~ 符號。
定義的對象在離開作用域時應該釋放其空間,特別是使用 new 關鍵字申請對象應手動使用 delete 進行刪除。

常數成員函數

常數關鍵字 constant 可以用於修飾成員函數。對於常數類型成員函數,其含義是函數內對象不會進行修改。常數的成員函數定義方法為在參數后添加 const 修飾符,例如

template <class Cmpt>
inline const Cmpt& Vector<Cmpt>::x() const
{
	return this->v_[X];
}

友元

友元 friend 代表一個函數或類可以訪問某個類的私有屬性。一個類可以聲明哪些類型為自己的友元,但是無法聲明自己為哪些類型的友元。

操作符

操作符定義了如何對特定的類型進行操作。標准操作符包括以下幾種

操作符應當被定義為成員函數或友元函數,函數名為 operatorX,其中 X 用對應的操作符號代替。

在 OpenFOAM 中為所有的類型都定義了對應的操作符,包括 iostream 符 <<>>

靜態成員

靜態成員在類之中具有單獨的實例,即所有對象中都一樣。靜態成員使用關鍵字 static,可以應用在數據成員或成員函數中。由於靜態成員不屬於任何一個特定的對象,因此調用時必須用類名進行調用,如

className::staticFunction(parameters);

繼承

一個類可以繼承另一個已有類的屬性,並擴展包含其他屬性。繼承的定義方法為

class newClass : public oldClass { ...members... }

在 OpenFOAM 中,類的繼承形式為

template <class Cmpt>
class Vector
:
	public VectorSpace<Vector<Cmpt>, Cmpt, 3>

這里,VectorVectorSpace 的一個子類。

子類的名字可以與父類相同,此時父類中所有同名成員會被隱藏,即使父類與子類成員函數的變量個數不同。

隱藏的父類成員可以通過 oldClass::member 方式訪問。在類中的定義的不同訪問屬性中,private 成員無法在子類中訪問,而 public 和 protected 屬性成員可以。子類可以有多個父類,從而合並各個類的特性。

虛函數

虛成員函數主要用於動態綁定,即根據運行時調用的方式來確定具體函數。
虛函數使用 virtual 關鍵字,通過使用指針指向父類的對象來實現動態綁定 p = new subClass (...parameters...),指針可以指向任何子類,從而使用 p->memberFunction 來調用具體函數。

具有至少一個虛函數的類為虛類,虛類無法實例化對象,主要作用是規定子類的定義方式。

模板

大部分類的定義都是針對特性數據類型,但是有些操作是與數據類型無關的,此時與其將相同的算法針對不同的類型定義許多遍,更常用的方法是定義模板使之適用於任意類型。
模板類在定義時在類前添加如下代碼

template<class T>

其中 T 是一般參數,代表任意類型,關鍵字 class 定義了 T 為類型變量。一般參數隨后在類的定義中使用指定的類型進行定義,模板類在構造對象時的形式為

templateClass<type> templateClassObject;

OpenFOAM 廣泛使用模板,為了使代碼易讀性更好,通常將模板類名字用 typedef 重新定義,例如

typedef List<vector> vectorList;

上面代碼將 vectorList 定義為 vector 數據類型的模板 List 類的別名。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM