1. 程式人生 > >C++基礎學習之程式設計模組(4)

C++基礎學習之程式設計模組(4)

函式和二維陣列

在C++中,二維陣列的定義完全與一維陣列不同:

int data[3][4] = {{1, 2, 3, 4}, {9, 8, 7, 6}, {2, 4, 6, 8}};

data不能當作是一維陣列的指標然後去訪問12個元素,data[0~2]每個都是一個一維陣列的指標,也就是說其實data是指標的指標。
所以在子函式中用的時候需要如下宣告:

int sun(int arr[][4], int size);

注意這裡把每個子指標指向的列數寫出來了,所以傳入的引數也只能是列數為4的二維陣列。如果不寫的話,直接寫成arr[][],那麼應該是可以傳入任意二維陣列的。

行內函數

行內函數其實就是相當於在把呼叫函式的過程替換成了直接執行程式碼段,也就是說一般的函式都是需要跳出去呼叫完再回到主函式,而行內函數直接就在編譯時把呼叫程式碼換成了函式程式碼段,所以節省時間的同時其實帶來了空間的負擔。這種函式的好處是當子函式內容不多,呼叫代價比直接執行用的時間長很多時,就有必要節省呼叫時間了,所以需要行內函數。
行內函數用法:

  • 在函式宣告前加上關鍵字inline
  • 或者在函式定義前加上關鍵字inline
    通常的做法是省略原型,將整個定義(即函式頭和所有函式程式碼)放在本應提供原型的地方。要注意的是行內函數不能遞迴。
    這個功能與C語言的巨集定義有些類似,但是比C語言巨集定義要好寫很多,好用很多。

引用變數

引用是已定義變數的別名。也就是說就是同一個變數有兩個名字。(python語言的特性裡有)。引用變數的主要用途是用作函式的形參,這樣函式將使用原始資料,而不是副本。這樣除指標以外,引用也為函式處理大型結構提供了一種非常方便的途徑,同時對於設計類來說,引用也是必不可少的。

建立引用變數

C和C++都使用&符號來指示變數的地址。C++給&符號賦予了另一個含義,將其用來宣告引用。例如,要將rodents作為rats變數的別名,可以這樣做:

int rats;
int & rodents = rats;	// makes rodents an alias for rats

其中,&不是地址運算子,而是型別識別符號的一部分。就像宣告中的char*指的是指向char的指標一樣,int&指的是指向int的引用。上述引用宣告允許將rats和rodents互換——它們指向相同的值和記憶體單元。
必須在宣告引用時將其初始化,不能像指標那樣先宣告再賦值。而且引用更接近const指標,必須在建立時進行初始化,一旦與某個變數關聯起來,就將一直效忠於它。也就是說,不能改。
按引用傳遞示例:

void grumpy(int &x);
int main()
{
	int times = 20;
	grumpy(times);
	...
}
void grumpy(int &x)	// 這裡使x成為times的別名,與times同一個變數,地址相同。
{
	...
}

按引用傳遞和安值傳遞看起來呼叫函式時是相同的。只能通過原型或函式定義才能知道是按引用傳遞的。之前說過,應在定義引用變數時對其進行初始化。函式呼叫使用實參初始化形參,因此函式的引用引數被初始化為函式呼叫傳遞的實參。所以指向的都是同一個值。

引用的屬性和特別之處

使用引用傳參時可能會改變原始的值,所以當想要使用引用傳參但不想改變原始值時,可以使用const,例如上例中可以這樣寫:void grumpy(const int &x),這樣如果子函式中對x進行更改編譯器就會報錯。其實當傳遞單個值時最好還是使用值傳遞,無需使用引用, 只有當想傳遞類,結構等較大的資料結構時,為了節省空間或者時間,可以使用引用傳參。
引用傳參傳遞的引數必須是一個變數,不能是算式,也就是說必須在記憶體中有地址而且有名字。否則C++會產生臨時變數,編譯器會發出警告。
應該儘可能的使用const:

  • 使用const可以避免無意中修改資料的程式設計錯誤;
  • 使用const使函式能夠處理const和非const實參,否則將只能接受非const資料;
  • 使用const引用使函式能夠正確生成並使用臨時變數。

將引用用於結構

使用結構引用引數的方式與使用基本變數引用相同,只需在宣告結構引數時使用引用運算子&即可。示例如下:

struct free_throws
{
	std::string name;
	int made;
	int attempts;
	float percent;
};
void set_pc(free_throws & ft);
// 或者
void display(const free_throws & tf);

引用也可以作為返回值,表示返回的是原始的值,否則返回一個拷貝值。

free_throws & accumulate(free_thorws & target, const free_throws & source);

返回引用時需要注意的是應避免返回函式終止時不再存在的記憶體單元引用。

將引用用於類物件

將類物件傳遞給函式時,C++通常的做法是使用引用。例如string就是一種類,可以像基本型別引用那樣使用類的引用。

函式模板

函式模板是通用的函式描述,也就是說,它們使用泛型來定義函式,其中泛型可用具體的型別(如int或double)替換。通過將型別作為引數傳遞給模板,可使編譯器生成該型別的函式。下面是一個建立交換模板的例子:

template <typename AnyType>
//或者更常用的一種形式
template<class T>
void Swap(T &a, T &b)
{
	T temp;
	temp = a;
	a = b;
	b = temp;
}

之後只要呼叫Swap函式,無論是什麼型別都可以迅速建立函式然後使用。一般來說都會把模板放在標頭檔案中,並在需要使用模板的檔案中包含標頭檔案。模板也可以被過載,只要寫兩個然後引數列表不同即可。
這種模板函式顯然對於陣列或者結構體無法操作,因此還有一種建立模板的方式叫做顯示具體化模板:

struct job
{
	char name[40];
	double salary;
	int floor;
};
template <> void Swap<job>(job &, job &);	// 原型

// 實現函式
template <> void Swap<job>(job &, job &)
{
	...
}

可以看出其實顯示具體化就是針對特定的資料結構寫一個特定資料結構的模板。
還有一種宣告是顯示例項化,就是宣告一個特定資料型別的函式供使用:

tmplate <> void Swap<int>(int &, int &);

直接指定型別,然後就可以在下面直接使用了,如果不用這句話就是隱式宣告,用了這句話就是顯示宣告,感覺沒啥用…(可能是顯示宣告之後更清楚吧…)
總之模板函式很強,所以C++專門建立了標準模板庫供人們使用,而使用方法就是類似上面的宣告就好(包含標頭檔案之後)。