l C++內嵌函式
內嵌函式是C++為提高程式運行速度所做的一項改進。相對於非內嵌函式,系統記憶體只存在一個此函數。如果調用,就會使程式指標來回跳躍,需要一定的開銷。而內嵌函式相當於靜態函數,系統記憶體裡在需要執行到的地方都有一個拷貝。基於內嵌函式這個特點,它應該經常被調用,或很短。
要使用這項特性:
n 在函式宣告前加上關鍵字inline
n 在函數定義前加上關鍵字inline
l 引用變數
C++新增了一種複合類型——引用變數。引用是已定義的變數的別名。
建立引用變數
eg:int rats;
cint & rodents=rats;
‘&’不是地址操作符,而是類型標識符的一部分。上述引用聲明表示rats和rodents具有相同的值和記憶體單元。
引用變數必須在聲明時將其初始化,而不能像指標那樣先聲明,再賦值:
eg:int rat;
int &rodent;
rodent=rat;
上述做法是禁止的。
引用經常被用作函數參數,使得函數中的變數名成為調用程式中的變數的別名。這種傳遞參數的方法稱為按引用傳遞。C++新增的這項特性是對C語言的超越,C語言只能按值傳遞。按值傳遞導致被調用函數使用調用程式中的值的拷貝。
eg:main()函數中調用swap(a,b),在函數swap聲明卻是這樣的swap(&a,&b)
以下是一個經典的說明按值傳遞,按引用傳遞和按指標傳遞的程式,其中引用和指標方法都成功實現了交換,但按值傳遞沒有完成任務。
// swaps.cpp -- swapping with references and with pointers
#include <iostream>
void swapr(int & a, int & b); // a, b are aliases for ints
void swapp(int * p, int * q); // p, q are addresses of ints
void swapv(int a, int b); // a, b are new variables
int main()
{
using namespace std;
int wallet1 = 300;
int wallet2 = 350;
cout << "wallet1 = $" << wallet1;
cout << " wallet2 = $" << wallet2 << endl;
cout << "Using references to swap contents:\n";
swapr(wallet1, wallet2); // pass variables
cout << "wallet1 = $" << wallet1;
cout << " wallet2 = $" << wallet2 << endl;
cout << "Using pointers to swap contents again:\n";
swapp(&wallet1, &wallet2); // pass addresses of variables
cout << "wallet1 = $" << wallet1;
cout << " wallet2 = $" << wallet2 << endl;
cout << "Trying to use passing by value:\n";
swapv(wallet1, wallet2); // pass values of variables
cout << "wallet1 = $" << wallet1;
cout << " wallet2 = $" << wallet2 << endl;
return 0;
}
void swapr(int & a, int & b) // use references
{
int temp;
temp = a; // use a, b for values of variables
a = b;
b = temp;
}
void swapp(int * p, int * q) // use pointers
{
int temp;
temp = *p; // use *p, *q for values of variables
*p = *q;
*q = temp;
}
void swapv(int a, int b) // try using values
{
int temp;
temp = a; // use a, b for values of variables
a = b;
b = temp;
}
按引用傳遞時,如果實參與引用參數不匹配,僅當參數為const引用時,C++將產生臨時變數。什麼時候產生臨時變數呢?
n 實參的類型正確,但不是左值(變數,數組元素,結構成員,引用,指標)
n 實參的類型不正確,但可以轉換成正確的類型
如果接受引用參數的函數意圖修改作為參數傳遞的變數,則建立臨時變數將阻止這種意圖的實現。實際上,對於形參為const引用的C++函數,如果實參不匹配,則行為類似於按值傳遞,為確保未經處理資料不被修改,將使用臨時變數來儲存值。
將引用用於結構體
eg:struct sysop
{
char name[26];
char quote[64];
int used;
}
const sysop &use(sysop & sysopref)
int main()
{
…
use(looper);
…
sysop copycat;
copycat=use(looper);
cout<<”use(looper): ”<<use(looper).used;
…
}
上述程式可以說明:
n 按引用傳遞可以傳遞結構體
n 按引用可以用來傳回值
n 使用函數調用來訪問結構的成員
返回引用時注意的問題
n 避免返回函數中的局部變數。
n 可以返回一個作為參數傳遞給函數的引用
n 使用new來分配新的儲存空間。
最後一點eg:
const sysop &clone(sysop &sysopref)
{
sysop *psysop = new sysop;
*psysop=sysopref;
return *psysop;
}
將引用用於類對象
string input;
getline(cin,input);
上面的語句示了一種對string類初始化的辦法。
eg:const string &version(string &s1,const string &s2);
int main()
{
…
string input;
string result;
result=version(input,”***”);
…
}
上述代碼這明可以將C-風格字串用作string對象引用參數,即string類定義了一種轉換:字串字面量、以Null 字元串結尾的char數組或指向char的指標變數可以轉換成string類對象。
對象、繼承、引用
能夠從一個類傳遞給別一個類的語言特性被稱為繼承,繼承的另一特性是,基類引用可以指向衍生類別引用。一個接受基類引用作為參數的函數,調用該函數時,可以將基類對象作為參數,也可以將衍生類別對象作為參數。
ios_base::fmtflags是一種儲存格式化資訊的資料類型。它可由setf()函數返回當前的有效設定。
ios_base::fmtflags initial;
initial=os.setf(ios_base::fixed);//定點顯示模式
os.precision(0)//顯示0位小數
os.setf(ios::showpoint);//顯示小數點模式
os.width(12)//下一次輸出使用的欄位寬度,作用只限於顯示下一個值,然後恢複預設。
使用按引用傳遞方式的指導原則:
n 資料對象是類對象,使用按引用
n 資料對象較大,可以使用按引用
n 資料對象是數組,要使用指標
l 預設參數
C++的函數可以有預設的參數。預設參數指的是當函數調用中省略了實參時自動使用的一個值。設定預設值的方法是將值賦給原型中的參數。對於帶參數列表的函數,必須從右向左添加預設值,實參按從左至右的順序依次被賦給相應的形參,而不能跳過任何參數。但如果有預設值,可以省略後面的參數。
eg:char *left(const char *str,int n=1);
int main()
{
…
char sample[80];
…
char *ps=left(sample)
…
}
l 函數重載
函數多態是C++新增的功能。預設參數讓您能夠使用不同數目的參數調用同一個函數,而函數多態(函數重載)讓您能夠使用多個同名的函數。
函數重載的關鍵是函數的參數列表——也稱為函數特徵標。如果兩個函數的參數數目和類型相同,同時參數的排列順序也相同,則它們的特徵標相同。
說明在有const變數的情況下,參數對應情況時,const變數對應const變數,非const變數對應非const變數。但是如果調用函數中與函數原型中的const變數不能相對應時:調用函數的非const變數可以對應函數原型中的const變數,但是調用函數中的const變數不能對應函數原型中的非const變數。
僅當函數基本上執行相同的任務,但使用不同形式的資料時,才應採用函數重載。
l 函數模板
函數模板是C++的一項新特性。
eg:template<class Any>
void swap(Any &a,Any &b)
{
Any temp;
temp=a;
a=b;
b=temp;
}
關鍵字template和class是必需的,除非可以使用關鍵字typename代替class。類型名(Any)可以任意選擇。
模板使用
eg:template <class Any>
void swap(Any &a,Any &b);
int main()
{
…
int i,j;
…
swap(i,j);
…
}
template <class Any>
void swap(Any &a,Any &b)
{
Any temp;
temp=a;
a=b;
b=temp;
}
可以像重載常規函數那樣重載模板定義。和常規重載一樣,被重載的模板的函數特徵標必須不同。
模板可以被執行個體化和具體化。在代碼中包含函數模板本身不會產生函數定義,它只是一個用於產生函數定義的方案。編譯器使用模板為特定類型產生函數定義時,得到的是模板執行個體。在上述執行個體中,swap(i,j)導致編譯器產生swap()的一個執行個體。這種執行個體化的方式被稱為隱式執行個體化。
顯示執行個體化
template void swap<int>(int,int);
編譯器看到上述聲明後,將使用swap()模板產生一個使用int類型的執行個體。該聲明的意思即是“使用swap()模板產生int類型的函數定義”
顯式具體化
template <> void swap<int>(int&,int&);
template<>void swap(int &,int&);
這些聲明的意思是“不要使用swap()模板來組建定義,而應使用獨立的、專門的函數定義顯式地為int類型產生函數定義”。它與執行個體化的區別是顯式具體化聲明在關鍵字template後包含”<>”,而顯式執行個體化沒有。
在有多個匹配的函數原型時,若有非模板函數,則(編譯器)選擇該函數。若皆為模板函數,則顯式具體化將優先於模板產生的版本。試圖在同一個編程單元中使用同一種類型的顯式執行個體化和顯式具體化將出錯。