OOP_由C到C++
由C到C++
OOP第一課
- C語言的局限
- C++的特點(diǎn)
- C++的程序特征
- C++程序的結(jié)構(gòu)特性
- C++程序的編輯、編譯和運(yùn)行
- ?C++對C的補(bǔ)充
C語言的局限
- 類型檢查機(jī)制相對較弱,使得程序中的一些錯(cuò)誤不能在編譯時(shí)由編譯器檢查出來。
- C語言本身沒有支持代碼重用的語言結(jié)構(gòu)
- 不適合開發(fā)大型程序,當(dāng)程序的規(guī)模達(dá)到一定的程度時(shí),程序員很難控制程序的復(fù)雜性。
C++的特點(diǎn)
C++繼承了C的優(yōu)點(diǎn),并有自己的特點(diǎn),主要有:
C++的程序特征
例1.1 輸出一行字符: “This is a C++ program.”。
程序如下:
#include <iostream> //包含頭文件iostream using namespace std; //使用命名空間std int main( ) {cout<<″This is a C++ program.″;return 0; }在運(yùn)行時(shí)會(huì)在屏幕上輸出以下一行信息:
This is a C++ program.
- 用main代表“主函數(shù)”的名字。每一個(gè)C++程序都必須有一個(gè) main 函數(shù)。main前面的int的作用是聲明函數(shù)的類型為整型。程序第6行的作用是向操作系統(tǒng)返回一個(gè)零值。如果程序不能正常執(zhí)行,則會(huì)自動(dòng)向操作系統(tǒng)返回一個(gè)非零值,一般為-1。
- 函數(shù)體是由大括號{}括起來的。本例中主函數(shù)內(nèi)只有一個(gè)以cout開頭的語句。注意C++所有語句最后都應(yīng)當(dāng)有一個(gè)分號。
- 再看程序的第1行“#include”,這不是Cpp的語句,而是Cpp的一個(gè)預(yù)處理命令,它以“#”開頭以與Cpp語句相區(qū)別,行的末尾沒有分號。
- #include <iostream>是一個(gè)“包含命令”,它的作用是將文件iostream的內(nèi)容包含到該命令所在的程序文件中,代替該命令行。文件iostream的作用是向程序提供輸入或輸出時(shí)所需要的一些信息。
- iostream是i-o-stream3個(gè)詞的組合,從它的形式就可以知道它代表“輸入輸出流”的意思,由于這類文件都放在程序單元的開頭,所以稱為“頭文件” (head file)。在程序進(jìn)行編譯時(shí),先對所有的預(yù)處理命令進(jìn)行處理,將頭文件的具體內(nèi)容代替#include命令行,然后再對該程序單元進(jìn)行整體編譯。
- 程序的第2行“using namespace std;”的意思是“使用命名空間std”。Cpp標(biāo)準(zhǔn)庫中的類和函數(shù)是在命名空間std中聲明的,因此程序中如果需要用到Cpp標(biāo)準(zhǔn)庫(此時(shí)就需要用#include命令行),就需要用“using namespace std;”作聲明,表示要用到命名空間std中的內(nèi)容。
- 在初學(xué)C++時(shí),對本程序中的第1,2行可以不必深究,只需知道: 如果程序有輸入或輸出時(shí),必須使用“#include ”命令以提供必要的信息,同時(shí)要用“using namespace std;”,使程序能夠使用這些信息,否則程序編譯時(shí)將出錯(cuò)。
例1.2 求a和b兩個(gè)數(shù)之和
// 求兩數(shù)之和 (本行是注釋行) #include <iostream> //預(yù)處理命令 using namespace std; //使用命名空間std int main( ) //主函數(shù)首部 { //函數(shù)體開始int a,b,sum; //定義變量cin>>a>>b; //輸入語句sum=a+b; //賦值語句cout<<″a+b=″<<sum<<endl; //輸出語句return 0; //如程序正常結(jié)束,向操作系統(tǒng)返回一個(gè)零值 } //函數(shù)結(jié)束本程序的作用是求兩個(gè)整數(shù)a和b之和sum。
第1行“//求兩數(shù)之和”是一個(gè)注釋行,Cpp規(guī)定在一行中如果出現(xiàn)“//” ,則從它開始到本行末尾之間的全部內(nèi)容都作為注釋。
例1.3 給兩個(gè)數(shù)x和y, 求兩數(shù)中的大者
#include <iostream> //預(yù)處理命令 using namespace std; int max(int x,int y) //定義max函數(shù),函數(shù)值為整型,形式參數(shù)x, y為整型 { //max函數(shù)體開始int z; //變量聲明,定義本函數(shù)中用到的變量z為整型if(x>y) z=x; //if語句,如果x>y, 則將x的值賦給zelse z=y; //否則,將y的值賦給zreturn(z); //將z的值返回,通過max帶回調(diào)用處 } //max函數(shù)結(jié)束 int main( ) //主函數(shù) { //主函數(shù)體開始int a,b,m; //變量聲明cin>>a>>b; //輸入變量a和b的值m=max(a,b); //調(diào)用max函數(shù),將得到的值賦給mcout<<″max=″<<m<<′\\n′; //輸出大數(shù)m的值return 0; //如程序正常結(jié)束,向操作系統(tǒng)返回一個(gè)零值 } //主函數(shù)結(jié)束本程序包括兩個(gè)函數(shù):主函數(shù)main和被調(diào)用的函數(shù)max。
程序運(yùn)行情況如下:
- 18 25 ↙ (輸入18和25給a和b)
- max=25 (輸出m的值)
注意輸入的兩個(gè)數(shù)據(jù)間用一個(gè)或多個(gè)空格間隔,不能以逗號或其他符號間隔。
在上面的程序中,max函數(shù)出現(xiàn)在main函數(shù)之前,因此在main函數(shù)中調(diào)用max函數(shù)時(shí),編譯系統(tǒng)能識(shí)別max是已定義的函數(shù)名。如果把兩個(gè)函數(shù)的位置對換一下,即先寫main函數(shù),后寫max函數(shù),這時(shí)在編譯main函數(shù)遇到max時(shí),編譯系統(tǒng)無法知道m(xù)ax代表什么含義,因而無法編譯,按出錯(cuò)處理。
為了解決這個(gè)問題,在主函數(shù)中需要對被調(diào)用函數(shù)作聲明。上面的程序可以改寫如下:
#include <iostream> using namespace std; int max(int x,int y); //對max函數(shù)作聲明 int main( ) {int a,b,c;cin>>a>>b;c=max(a,b); //調(diào)用max函數(shù)例1.3 給兩個(gè)數(shù)x和y, 求兩數(shù)中的大者。cout<<″max=″<<c<<endl;return 0; } int max(int x,int y) //定義max函數(shù) {int z;if(x>y) z=x;else z=y;return(z); }只要在被調(diào)用函數(shù)的首部的末尾加一個(gè)分號,就成為對該函數(shù)的函數(shù)聲明。函數(shù)聲明的位置應(yīng)當(dāng)在函數(shù)調(diào)用之前。
C++程序的結(jié)構(gòu)特性
一個(gè)面向?qū)ο蟮腃++程序一般由類的聲明和類的使用兩大部分組成。
類的使用部分一般由主函數(shù)及有關(guān)子函數(shù)組成。
典型的C++程序結(jié)構(gòu)
#include <iostream.h> //類的聲明部分 class A{int x,y,z;……fun( ){……}…… }; //類的使用部分 int main() {A a;……a.fun();return 0; }在C++程序中,程序設(shè)計(jì)始終圍繞“類”展開。通過聲明類,構(gòu)建了程序所要完成的功能,體現(xiàn)了面向?qū)ο蟪绦蛟O(shè)計(jì)的思想。
C++程序的編輯、編譯和運(yùn)行
C++源程序文件的擴(kuò)展名為.CPP
可以用多種編譯器編輯、編譯和運(yùn)行
C++對C的補(bǔ)充
1. 注釋與續(xù)行
- 注釋符:“/*”和“*/” 或“//” 。
Cpp新增了注釋語句,它由“//”開始,到行尾結(jié)束。
例如:
- 續(xù)行符:“\”(反斜杠)。作用是當(dāng)一個(gè)語句太長時(shí)可以用該符號把它分段寫在幾行中。
例:
2. 輸入輸出流
C中I/O操作出現(xiàn)的問題:
int i; float f; scanf(“%f”,i); printf( “%d”,d);Cpp中使用更安全更方便的方法:
int i; float f; cin >> i; cout << f;cout和cin分別是C++的標(biāo)準(zhǔn)輸出流和輸入流。 Cpp支持重定向,但一般cout指的是屏幕, cin指的是鍵盤。
操作符“<<”和“>>”除了具有C語言中定義的左移和右移的功能外,在這里符號“<<”是把右方的參數(shù)寫到標(biāo)準(zhǔn)輸出流cout中;相反,符號“>>”則是將標(biāo)準(zhǔn)輸入流的數(shù)據(jù)賦給右方的變量。
例1.4 一個(gè)完整的C++程序
#include <iostream.h> int main() {char name[20];cout << "Hello, your name: ";cin >> name;cout << name;return 0; }注意:
- 程序中必須包含頭文件iostream.h
- cin和>>,cout和<<配套使用
cin可以輸入多個(gè)數(shù)據(jù),但要用空白符隔開(tab,空格,回車)
如: cin >> a >> b >> c;
換行符:‘\n’或endl
如: cout << “x=” << x << endl; cout << “x=” << x << ‘\n’;
使用cout和cin時(shí),也可以對輸入和輸出的格式進(jìn)行控制,比如可用不同的進(jìn)制方式顯示數(shù)據(jù),只要設(shè)置轉(zhuǎn)換基數(shù)的操作符dec、hex和oct即可。
例1.5 操作符dec、 hex和oct的使用
#include<iostream.h> void main() {int x=25;cout << hex << x << ' ' << dec << x << ' ' << oct << x << '\n'; }輸出結(jié)果為: 19 25 31
3. 靈活的變量說明
定義變量的位置
在程序中的不同位置采用不同的變量定義方式,決定了該變量具有不同的特點(diǎn)。變量的定義一般可有以下三種位置:
(1) 在函數(shù)體內(nèi)部
在函數(shù)體內(nèi)部定義的變量稱為局部變量,這種局部變量只在進(jìn)入定義它的函數(shù)體時(shí)起作用,離開該函數(shù)體后該變量就消失(被釋放),即不再起作用。因此,不同函數(shù)體內(nèi)部可以定義相同名稱的變量,而互不干擾。
(2) 形式參數(shù)
當(dāng)定義一個(gè)有參函數(shù)時(shí),函數(shù)名后面括號內(nèi)的變量,統(tǒng)稱為形式參數(shù)。
(3) 全局變量
在所有函數(shù)體外部定義的變量,其作用范圍是整個(gè)程序,并在整個(gè)程序運(yùn)行期間有效。
- 在C語言中,全局變量聲明必須在任何函數(shù)之前,局部變量必須集中在可執(zhí)行語句之前。
- Cpp中的變量聲明非常靈活,它允許變量聲明與可執(zhí)行語句在程序中交替出現(xiàn)。
例如
4. 結(jié)構(gòu)、聯(lián)合和枚舉名
在C++中,結(jié)構(gòu)名、聯(lián)合名、枚舉名都是類型名。在定義變量時(shí),不必在結(jié)構(gòu)名、聯(lián)合名或枚舉名前冠以struct、union或enum。
例如:
enum boole{FALSE,TRUE}; struct string{char *string;int length; }; union number{int i;float f; };在傳統(tǒng)的C中,定義變量時(shí),必須寫成:
enum boole done; struct string str; union number x;但是,在C++中,可以說明為:
boole done; string str; number x;5. 函數(shù)原型
C語言建議編程者為程序中的每一個(gè)函數(shù)建立原型,而Cpp要求為每一個(gè)函數(shù)建立原型,以說明函數(shù)的名稱、參數(shù)類型與個(gè)數(shù),以及函數(shù)返回值的類型。
其主要目的是讓C++編譯程序進(jìn)行類型檢查,即形參與實(shí)參的類型匹配檢查,以及返回值是否與原型相符,以維護(hù)程序的正確性。
例如
int sum(int a,int b); //是函數(shù)sum的原型- 函數(shù)原型語法的一般形式為:返回類型 函數(shù)名(參數(shù)表);
- 函數(shù)原型是一條語句,它必須以分號結(jié)束。
例1.6 函數(shù)原型的說明
#include<iostream.h> void write(char *s); void main() {write("Hello,world!");} void write(char *s) {cout<<s;}在程序中,要求一個(gè)函數(shù)的原型出現(xiàn)在該函數(shù)的調(diào)用語句之前。
說明:
- 函數(shù)原型的參數(shù)表中可不包含參數(shù)的名字,而只包含它們的類型。例如: long Area(int ,int);
- 函數(shù)定義由函數(shù)首部和函數(shù)體構(gòu)成。函數(shù)首部和函數(shù)原型基本一樣,但函數(shù)首部中的參數(shù)必須給出名字而且不包含結(jié)尾的分號。
- Cpp的參數(shù)說明必須放在函數(shù)說明后的括號內(nèi),不可將函數(shù)參數(shù)說明放在函數(shù)首部和函數(shù)體之間。這種方法只在C中成立。
- 主函數(shù)不必進(jìn)行原型說明,因?yàn)樗豢闯勺詣?dòng)說明原型的函數(shù)。
- 原型說明中沒有指定返回類型的函數(shù)(包括主函數(shù)main),Cpp默認(rèn)該函數(shù)的返回類型是int
- 如果一個(gè)函數(shù)沒有返回值,則必須在函數(shù)原型中注明返回類型為void,主函數(shù)類似處理。
- 如果函數(shù)原型中未注明參數(shù),Cpp假定該函數(shù)的參數(shù)表為空(void)。
6. const修飾符
- 在C中,習(xí)慣使用#define定義常量。
一般格式: #define 宏名 常數(shù)
如
#define PI 3.14 ………… s = 2 * PI * r; …………- C++利用const定義正規(guī)常數(shù)
一般格式: const 數(shù)據(jù)類型標(biāo)識(shí)符 常數(shù)名=常量值;
采用這種方式定義的常量是類型化的,它有地址,可以用指針指向這個(gè)值,但不能修改它。
說明:
數(shù)據(jù)類型是一個(gè)可選項(xiàng),用來指定常數(shù)值的數(shù)據(jù)類型,如果省略了該數(shù)據(jù)類型,那么編譯程序認(rèn)為它是 int 類型。
如: const int a=10; 表示定義了一個(gè)初始值為10的整型常量,它在程序中不可改變,但可用于表達(dá)式的計(jì)算中。
例2.6 #define的不安全性
#include "iostream.h" main() {int a=1;#define T1 a+a#define T2 T1-T1cout<<"T2 is "<<T2<<endl;return 0; }但實(shí)際的輸出是: T2 is 2
const作用與#define相似,但消除了#define的不安全性。
如果用const取代了兩個(gè)#define,就不會(huì)引起這個(gè)錯(cuò)誤。
#include<iostream.h> int main() {int a=1;const T1=a+a;const T2=T1-T1;cout <<"T2 is"<<T2<<endl;return 0; }const可以與指針一起使用
- (1)指向常量的指針:一個(gè)指向常量的指針變量。
例如:
const char* pc=“abcd”; //聲明指向常量的指針 pc[3]=‘x’; //錯(cuò)誤 pc=“efgh”; //允許- (2)常指針:把指針本身,而不是它指向的對象聲明為常量。
例如:
char* const pc=“abcd”; //常指針 pc[3]=‘x’; //合法 pc=“efgh”; //出錯(cuò)創(chuàng)建一個(gè)常指針,就是創(chuàng)建一個(gè)不能移動(dòng)的固定指針,但是它所指的數(shù)據(jù)可以改變。例如:
- (3)指向常量的常指針:這個(gè)指針本身不能改變,它所指向的值也不能改變。
要聲明一個(gè)指向常量的常指針,二者都要聲明為const。
例如:
const char* const pc=“abcd”; //指向常量的常指針 pc[3]=‘x’; //出錯(cuò) pc=“efgh”; //出錯(cuò)這個(gè)語句的含義是:聲明了一個(gè)名為pc的指針變量,它是一個(gè)指向字符型常量的常指針,用“abcd”的地址初始化該指針。
說明
- (1). 如果用const定義的是一個(gè)整型常量,關(guān)鍵詞int可以省略。所以下面的兩語句是等價(jià)的
- const int bufsize=200;
- const bufsize=200;
- (2). 常量一旦被建立,在程序的任何地方都不能再更改。
- (3). 與#define定義的常量有所不同,const定義的常量可以有自己的數(shù)據(jù)類型,這樣C++的編譯程序可以進(jìn)行更加嚴(yán)格的類型檢查,具有良好的編譯時(shí)的檢測性。
(4). 函數(shù)參數(shù)也可以用const說明,用于保證實(shí)參在該函數(shù)內(nèi)部不被改動(dòng),大多數(shù)C++編譯器能對具有const參數(shù)的函數(shù)進(jìn)行更好的代碼優(yōu)化。
例如:通過函數(shù)i_Max求出整型數(shù)組a[200]中的最大值,函數(shù)原型應(yīng)該是:int i_Max(const int* ptr);
這樣做的目的是確保原數(shù)組的數(shù)據(jù)不被破壞,即在函數(shù)中對數(shù)組元素的操作只許讀,而不許寫。調(diào)用時(shí)的格式可以是:i_Max(a);
7. void型指針
void 通常表示無值,但將void作為指針的類型時(shí),它卻表示不確定的類型。
這種void型指針是一種通用型指針,也就是說任何類型的指針值都可以賦給void類型的指針變量。
例如下面的程序段
void pa; //錯(cuò)誤,不能聲明void類型的指針變量 void* pc; //正確,可以聲明void類型的指針 int i=456; char c=‘a(chǎn)’; pc=&i; pc=&c;void型指針可以接受任何類型的指針的賦值,但對已獲值的void型指針,對它在進(jìn)行處理,如輸出或傳遞指針值時(shí),則必須進(jìn)行強(qiáng)制類型轉(zhuǎn)換,否則會(huì)出錯(cuò)。
#include <iostream.h> main() {void *pc;int i=456;char c='a';pc=&i;cout<<*(int *)pc<<endl;pc=&c;cout<<*(char *)pc<<endl;return 0; }8. 內(nèi)聯(lián)函數(shù)
調(diào)用函數(shù)時(shí)系統(tǒng)要付出一定的開銷,用于信息入棧出棧和參數(shù)傳遞等。特別是對于那些函數(shù)體較小但調(diào)用又較頻繁的函數(shù),計(jì)算機(jī)的開銷相對就比較可觀。
在C語言中,用宏替換,可解決這個(gè)問題。例如,有如下的函數(shù):
add(int x,int y) {return x+y; }用宏替換時(shí),上面的函數(shù)功能可寫為:
#define add(x,y) x+yC++引進(jìn)了內(nèi)聯(lián)函數(shù)(inline function)的概念。
宏替換實(shí)質(zhì)上是文字替換。內(nèi)聯(lián)函數(shù)與一般函數(shù)不同的是,在進(jìn)行程序的編譯時(shí),編譯器將內(nèi)聯(lián)函數(shù)的目標(biāo)代碼作拷貝并將其插入到調(diào)用內(nèi)聯(lián)函數(shù)的地方。
例1.7 內(nèi)聯(lián)函數(shù)的使用
#include "iostream.h" inline double circle(double r) {return 3.1416*r*r;} int main() {for(int i=1;i<=3;i++)cout<<"r="<<i<<" area="<<circle(i)<<endl;return 0; }說明:
- (1). 內(nèi)聯(lián)函數(shù)在第一次被調(diào)用前必須進(jìn)行聲明或定義,否則編譯器將無法知道應(yīng)該插入什么代碼。
- (2). C++的內(nèi)聯(lián)函數(shù)具有與C中的宏定義#define相同的作用和類似機(jī)理,但消除了#define的不安全性。
- (3). 內(nèi)聯(lián)函數(shù)體內(nèi)一般不能有循環(huán)語句和開關(guān)語句。
- (4). 后面類結(jié)構(gòu)中所有在類說明體內(nèi)定義的函數(shù)都是內(nèi)聯(lián)函數(shù)。
- (5). 通常較短的函數(shù)才定義為內(nèi)聯(lián)函數(shù)。
9. 帶有缺省參數(shù)值的函數(shù)
在C++中,函數(shù)的參數(shù)可以有缺省值。
當(dāng)調(diào)用有缺省參數(shù)的函數(shù)時(shí),如果相應(yīng)的參數(shù)沒有給出實(shí)參,則自動(dòng)用相應(yīng)的缺省參數(shù)值作為其實(shí)參。
函數(shù)的缺省參數(shù),是在函數(shù)原型中給定的。
例如:
int init(int x=5, int y=10); init(100,80); //允許 init(25); //允許 init(); //允許說明:
(1)在函數(shù)原型中,所有取缺省值的參數(shù)必須出現(xiàn)在不取缺省值的參數(shù)的右邊。
- int fun(int I,int j=5,int k); 錯(cuò)誤
- int fun(int I,int k,int j=5); 正確
(2)在函數(shù)調(diào)用時(shí),若某個(gè)參數(shù)省略,則其后的參數(shù)皆應(yīng)省略而采用缺省值。
- init (,20) 錯(cuò)誤
例.編寫一個(gè)帶有默認(rèn)參數(shù)的函數(shù),使得在默認(rèn)情況下顯示兩個(gè)整數(shù)的較大者,否則顯示兩個(gè)整數(shù)的較小者。
int main() {void showValue(int x, int y, bool Max = true); // 聲明函數(shù)int a = 5, b = 10;showValue(a,b);showValue(a,b,false);return 0; } void showValue(int x, int y, bool Max = true) // 定義函數(shù) {if(Max)cout << “the bigger value is: " << (x>y)?x:y << endl;elsecout << "the smaller value is: " << (x<y)?x:y << endl; }10. 函數(shù)重載
(1) 什么是函數(shù)重載
函數(shù)重載是指一個(gè)函數(shù)可以和同一作用域中的其他函數(shù)具有相同的名字,但這些同名函數(shù)的參數(shù)類型、參數(shù)個(gè)數(shù)不同。如:
#include <iostream.h> void whatitis(int i) { cout<<"this is integer"<<i<<endl;} void whatitis(char c[]) { cout<<“this is string”<<c<<endl; } main() {int i=1;char c[]="abcdef";whatitis(i);whatitis(c); }在本例中定義了兩個(gè)名稱都叫whatitis的函數(shù),但它們的形參類型不同。因此,這兩個(gè)函數(shù)就是重載函數(shù)。
(2) 為什么要使用函數(shù)重載
在原有C語言中,每個(gè)函數(shù)必須有其唯一的名稱,這樣的缺點(diǎn)是所有具有相同功能、而只是函數(shù)參數(shù)不一樣的函數(shù),就必須用一個(gè)不同的名稱.
而C++中采用了函數(shù)重載后,對于具有同一功能的函數(shù),如果只是由于函數(shù)參數(shù)類型不一樣,則可以定義相同名稱的函數(shù)。
(3) 匹配重載函數(shù)的順序
由于重載函數(shù)具有相同的函數(shù)名,在進(jìn)行函數(shù)調(diào)用時(shí),系統(tǒng)一般按照調(diào)用函數(shù)時(shí)的參數(shù)個(gè)數(shù)、類型和順序來確定被調(diào)用的函數(shù)。
具體來說,按以下三個(gè)步驟的先后次序找到并調(diào)用那個(gè)函數(shù):
- (1)尋找一個(gè)嚴(yán)格的匹配,即:調(diào)用與實(shí)參的數(shù)據(jù)類型、個(gè)數(shù)完全相同的那個(gè)函數(shù)。
- (2)通過內(nèi)部轉(zhuǎn)換尋求一個(gè)匹配,即:通過(1)的方法沒有找到相匹配的函數(shù)時(shí),則由C++系統(tǒng)對實(shí)參的數(shù)據(jù)類型進(jìn)行內(nèi)部轉(zhuǎn)換,轉(zhuǎn)換完畢后,如果有匹配的函數(shù)存在,則執(zhí)行該函數(shù)。
- (3)通過用戶定義的轉(zhuǎn)換尋求一個(gè)匹配,若能查出有唯一的一組轉(zhuǎn)換,就調(diào)用那個(gè)函數(shù)。即:在函數(shù)調(diào)用處由程序員對實(shí)參進(jìn)行強(qiáng)制類型轉(zhuǎn)換,以此作為查找相匹配的函數(shù)的依據(jù)。
例1.8 重載例子
#include <iostream.h> void print(double d) { cout<<"this is a double "<<d<<"\n"; } void print(int i) { cout<<"this is an integer "<<i<<"\n"; } void main() {int x=1,z=10;float y=1.0;char c='a';print(x); //按規(guī)則(1)自動(dòng)匹配函數(shù)void print(int i)print(y); //按規(guī)則(2)通過內(nèi)部轉(zhuǎn)換匹配函數(shù) void print(double i)//因?yàn)橄到y(tǒng)能自動(dòng)將float型轉(zhuǎn)換成double型print(c); //按規(guī)則(2)通過內(nèi)部轉(zhuǎn)換匹配函數(shù) void print(int i)//因?yàn)橄到y(tǒng)能自動(dòng)將char型轉(zhuǎn)換成int型print(double(z)); //按規(guī)則(3)匹配void print(double i)//因?yàn)槌绦蛑袑?shí)參z強(qiáng)制轉(zhuǎn)換為double型。 }例 重載例子
編寫一個(gè)程序,用來求兩個(gè)整數(shù)或3個(gè)整數(shù)中的最大數(shù)。如果輸入兩個(gè)整數(shù),程序就輸出這兩個(gè)整數(shù)中的最大數(shù),如果輸入3個(gè)整數(shù),程序就輸出這3個(gè)整數(shù)中的最大數(shù)。
#include <iostream> using namespace std; int main( ) {int max(int a,int b,int c); //函數(shù)聲明int max(int a,int b); //函數(shù)聲明int a=8, b=-12, c=27;cout<<"max(a,b,c)="<<max(a,b,c)<<endl; //3個(gè)整數(shù)中的最大者cout<<"max(a,b)="<<max(a,b)<<endl; //2個(gè)整數(shù)中的最大者 } int max(int a,int b,int c) {if(b>a) a=b;if(c>a) a=c;return a; } int max(int a,int b) {if(a>b) return a;else return b; }(4) 定義重載函數(shù)時(shí)的注意事項(xiàng)
- 重載函數(shù)間不能只是函數(shù)的返回值不同,應(yīng)至少在形參的個(gè)數(shù)、參數(shù)類型或參數(shù)順序上有所不同。
如:
- 應(yīng)使所有的重載函數(shù)的功能相同。如果讓重載函數(shù)完成不同的功能,會(huì)破壞程序的可讀性。
(5) 函數(shù)模板
1) 函數(shù)模板 (function template):
建立一個(gè)通用函數(shù),其函數(shù)類型和形參類型不具體指定,而是一個(gè)虛擬類型。
2) 應(yīng)用情況:
凡是函數(shù)體相同的函數(shù)都可以用這個(gè)模板來代替,不必定義多個(gè)函數(shù),只需在模板中定義一次即可。在調(diào)用函數(shù)時(shí)系統(tǒng)會(huì)根據(jù)實(shí)參的類型來取代模板中的虛擬類型,從而實(shí)現(xiàn)了不同函數(shù)的功能。
3) 一般形式:
- template < typename T> // 模板頭 通用函數(shù)定義
- template <class T> // 模板頭 通用函數(shù)定義
- template <class T1,typename T2> // 多個(gè)參數(shù) 通用函數(shù)定義
說明: class與typename可以通用
#include <iostream> using namespace std; template<typename T> // 模板聲明,其中T為類型參數(shù) T max(T a, T b) // 定義一個(gè)通用函數(shù), T作為虛擬的類型名 {if(b>a) return b;else return a; } //template <typename T> T max(T a, T b) //{ //… //} int main( ) {int i1=111, i2=222, i;double d1=12.34, d2=56.78,d;i=max(i1,i2); // 調(diào)用模板函數(shù),此時(shí)T被 int 取代d=max(d1,d2,d3); // 調(diào)用模板函數(shù),此時(shí)T被 double 取代cout<<"i_max=" << i <<endl;cout<<"f_max=" <<f<<endl;return 0; }函數(shù)模板說明:
1) 在對程序進(jìn)行編譯時(shí),遇到第13行調(diào)用函數(shù)max(i1,i2), 編譯系統(tǒng)會(huì)將函數(shù)名max與模板max相匹配,將實(shí)參的類型取代了函數(shù)模板中的虛擬類型T。此時(shí)相當(dāng)于已定義了一個(gè)函數(shù),然后調(diào)用它。
int max(int a,int b) { if(b>a) a=b; if(c>a) a=c; return a; }2) 與重載函數(shù)比較:用函數(shù)模板比函數(shù)重載更方便,程序更簡潔。但應(yīng)注意它只適用于:函數(shù)的參數(shù)個(gè)數(shù)相同而類型不同,且函數(shù)體相同的情況。如果參數(shù)的個(gè)數(shù)不同,則不能用函數(shù)模板;
3) main函數(shù)不能定義為模板函數(shù)。
11. 作用域標(biāo)示符::
通常情況下,如果有兩個(gè)同名變量,一個(gè)是全局的,另一個(gè)是局部的,那么局部變量在其作用域內(nèi)具有較高的優(yōu)先權(quán)。
下面的例子說明了這個(gè)問題。
#include "iostream.h" int avar=10; main( ) {int avar;avar=25;cout<<"avar is"<<avar<<endl;return 0; }如果希望在局部變量的作用域內(nèi)使用同名的全局變量,可以在全局變量加上“::”,此時(shí)::avar代表全局變量avar
#include <iostream.h> int avar=10; main() { int avar; avar=25; cout<<"local avar ="<<avar<<endl; cout<<"global avar="<<::avar<<endl; return 0; }12. 無名聯(lián)合
無名聯(lián)合是C++中的一種特殊聯(lián)合,可以聲明一組無標(biāo)記名共享同一段內(nèi)存地址的數(shù)據(jù)項(xiàng)。如:
union{int i;float f; }在此無名聯(lián)合中,聲明了變量i和f具有相同的存儲(chǔ)地址。無名聯(lián)合可通過使用其中數(shù)據(jù)項(xiàng)名字直接存取,例如可以直接使用上面的變量i或f,如:i=20;
13. 強(qiáng)制類型轉(zhuǎn)換
在C中數(shù)據(jù)類型轉(zhuǎn)換的一般形式:(數(shù)據(jù)類型標(biāo)識(shí)符)表達(dá)式
int i=10; float x=(float) i;C++支持這樣的格式,還提供了一種更為方便的函數(shù)調(diào)用方法,即將類型名作為函數(shù)名使用,使得類型轉(zhuǎn)換的執(zhí)行看起來好像調(diào)用了一個(gè)函數(shù)。形式為:數(shù)據(jù)類型標(biāo)識(shí)符 (表達(dá)式)
int i=10; float x=float(i);以上兩種方法C++都接受,但推薦使用后一種方式。
14. 動(dòng)態(tài)內(nèi)存分配
作為對C語言中malloc和free的替換,C++引進(jìn)了new和delete操作符。它們的功能是實(shí)現(xiàn)內(nèi)存的動(dòng)態(tài)分配和釋放。
動(dòng)態(tài)分配new的一般形式是:
- 指針變量=new 數(shù)據(jù)類型;
- 指針變量=new 數(shù)據(jù)類型(初始值);
釋放由new操作動(dòng)態(tài)分配的內(nèi)存時(shí),用delete操作。
它的一般形式是:delete 指針變量;
delete a; delete b;例1.9 操作符new和delete的使用
#include <iostream.h> main() {int *p; // 聲明一個(gè)整型指針變量pp=new int; // 動(dòng)態(tài)分配一個(gè)存放int型數(shù)據(jù)的內(nèi)存空間,并將首地址賦給p*p=10;cout<<*p;delete p; // 釋放指針變量p指向的內(nèi)存空間return 0; }例1.10 將new和delete用于結(jié)構(gòu)類型
#include<iostream.h> #include<string.h> struct person {char name[20];int age; }; main() {person *p;p=new person;strcpy(p->name, "Wang Fun");p->age=23;cout<<"\n"<<p->name<<" "<<endl<<p->age;delete p;return 0; }與C的內(nèi)存動(dòng)態(tài)分配和釋放操作(malloc和free)相比,C++提供的動(dòng)態(tài)分配有以下優(yōu)點(diǎn)
- (1) new和delete 操作自動(dòng)計(jì)算需要分配和釋放類型的長度。這不但省去了用sizeof計(jì)算長度的步驟,更主要的是避免
了內(nèi)存分配和釋放時(shí)因長度出錯(cuò)帶來的嚴(yán)重后果; - (2) new操作自動(dòng)返回需分配類型的指針, 無需使用強(qiáng)制類型轉(zhuǎn)換;
- (3) new操作能初始化所分配的類型變量。
- (4) new和delete都能可以被重載,允許建立自定義的內(nèi)存管理法。
對使用new和delete的幾點(diǎn)說明:
- (1)用new分配的空間,使用結(jié)束后應(yīng)該用delete顯示的釋放,否則這部分空間將不能回收而變成死空間。
- (2)使用new動(dòng)態(tài)分配內(nèi)存時(shí),如果沒有足夠的內(nèi)存滿足分配要求, new將返回空指針(NULL)。因此通常要對內(nèi)存的動(dòng)態(tài)分配是否成功進(jìn)行檢查。
例1.11 對內(nèi)存的動(dòng)態(tài)分配是否成功進(jìn)行檢查
#include <iostream.h> main() {int * p;p=new int;if(!p){cout<<"allocation failure\n";return 1;}*p=20;cout<<*p;delete p;return 0; }(3) 使用new可以為數(shù)組動(dòng)態(tài)分配內(nèi)存空間這是需要在類型后面綴上數(shù)組大小。其語法形式為:
指針變量=new 類型名 [下標(biāo)表達(dá)式];- 例如: int *pi=new int[10];
這時(shí)new為具有10個(gè)元素的整型數(shù)組分配了內(nèi)存空間,并將首地址賦給了指針pi。 - 使用new為多維數(shù)組分配空間時(shí),必須提供所有維的大小,
- 如: int *pi=new int[2][3][4];
- 其中第一維的界值可以是任何合法的表達(dá)式,如:int i=3; int *pi=new int[ i ][2][3];
- 例如: int *pi=new int[10];
- (4) 釋放動(dòng)態(tài)分配的數(shù)組存儲(chǔ)區(qū)時(shí),可使用delete運(yùn)算符,其語法形式為: delete [ ]指針變量;
- 無須指出空間的大小,但老版本的Cpp要求在delete的方括號中標(biāo)出數(shù)字,以告訴Cpp要釋放多少個(gè)元素所占的空間。例如:delete []pi; delete [10]pi;
(5) new可在為簡單變量分配內(nèi)存空間的同時(shí),進(jìn)行初始化。這時(shí)的語法形式為:指針變量=new 類型名(初始值列表)
例 1.12 new為簡單變量分配內(nèi)存空間的同時(shí),進(jìn)行初始化
#include <iostream.h> int main() {int *p;p=new int(99); // 動(dòng)態(tài)分配內(nèi)存,并將99作為初始值賦給它if (!p){cout<<"allocation failure\n";return 1;}cout<<*p;delete p;return 0; }例 1.13 給數(shù)組分配內(nèi)存空間的例子。
#include <iostream.h> main() {double *s;s=new double[10];if(!s){cout<<"alocation failure\n";return 1;}for(int i=0;i<10;i++)s[i]=100.00+2*i;for(int i=0;i<10;i++)cout<<s[i]<<" ";delete []s;return 0; }15. 引用
(1) 引用的概念
引用就是某一變量(目標(biāo))的一個(gè)別名,這樣對引用的操作就是對目標(biāo)的操作。
引用的聲明方法: 類型標(biāo)識(shí)符 &引用名=目標(biāo)變量名;
int a; int &ra=a; //定義引用ra,它是變量a的引用,即別名說明:
- (1) &在此不是求地址運(yùn)算,而是起標(biāo)識(shí)作用。
- (2) 類型標(biāo)識(shí)符是指目標(biāo)變量的類型。
- (3)聲明引用時(shí),必須同時(shí)對其進(jìn)行初始化。
- (4)引用聲明完畢后,相當(dāng)于目標(biāo)變量名有兩個(gè)名稱。
- (5)聲明一個(gè)引用,不是新定義了一個(gè)變量,系統(tǒng)并不給引用分配存儲(chǔ)單元。
例1.15 引用的使用
#include <iostream.h> void main() {int i;int &j=i;i=30;cout<<"i="<<i<<"j="<<j<<"\n";j=80;cout<<"i="<<i<<"j="<<j<<"\n";cout<<"Address of i"<<&i<<"\n";cout <<"Address of j"<<&j<<"\n"; }結(jié)果:
i=30 j=30 i=80 j=80 Address of oxfff4 Address of oxfff4例1.16 使用引用可以簡化程序
#include<iostream.h> main() {int i=15;int* iptr=&i;int & rptr=i;cout<<" i is "<<i<<endl;cout<<" *iptr is "<<*iptr<<endl;cout<<" rptr is "<<rptr<<endl;i=29;cout<<" After changing i to 29: "<<endl;cout<<" i is "<<i<<endl;cout<<" *iptr is "<<*iptr<<endl;cout<<" rptr is "<<rptr<<endl;return 0; }運(yùn)行結(jié)果:
i is 15 *iptr is 15 rptr is 15 After changing i to 29: i is 29 *iptr is 29 rptr is 29(2) 引用的使用
- (1)引用名可以是任何合法的變量名。除了用作函數(shù)的參數(shù)或返回類型外,在聲明時(shí),必須立即對它進(jìn)行初始化,不能聲明完后再賦值。
- (2)引用不能重新賦值,不能再把該引用名作為其他變量名的別名,任何對該引用的賦值就是該引用對應(yīng)的目標(biāo)變量名的賦值。對引用求地址,就是對目標(biāo)變量求地址。
- (3)由于指針變量也是變量,所以,可以聲明一個(gè)指針變量的引用。方法是: 類型標(biāo)識(shí)符 *&引用名=指針變量名;
- (4)引用是對某一變量或目標(biāo)對象的引用,它本身不是一種數(shù)據(jù)類型,因此引用本身不占存儲(chǔ)單元,這樣,就不能聲明引用的引用,也不能定義引用的指針。
(5)不能建立數(shù)組的引用,因?yàn)閿?shù)組是一個(gè)由若干個(gè)元素所組成的集合,所以就無法建立一個(gè)數(shù)組的別名。
- (6)不能建立空指針的引用
- (7)也不能建立空類型void的引用,因?yàn)楸M管在C++語言中有void數(shù)據(jù)類型,但沒有任何一個(gè)變量或常量屬于void類型。
- (8) 盡管引用運(yùn)算符與地址操作符使用相同的的符號,但時(shí)不一樣的。引用僅在聲明時(shí)帶有引用運(yùn)算符&,以后就像普通變量一樣使用,不能再帶&。其他場合使用的&都是地址操作符。
(3) 用引用作為函數(shù)的參數(shù)
- 一個(gè)函數(shù)的參數(shù)也可定義成引用的形式
在主調(diào)函數(shù)的調(diào)用點(diǎn)處,直接以變量作為實(shí)參進(jìn)行調(diào)用即可,不需要實(shí)參變量有任何的特殊要求。
swap(a,b); //直接以a和b作為實(shí)參調(diào)用swap函數(shù)例1.17 采用指針參數(shù)的例子
#include<iostream.h> void swap(int *m, int *n) {int temp;temp=*m;*m= *n;*n=temp; } main() {int a=5, b=10;cout<<"a="<<a<<" b="<<b<<endl;swap(&a, &b);cout<<"a="<<a<<" b="<<b<<endl;return 0; }運(yùn)行結(jié)果:
a=5 b=10 a=10 b=5例1.18 采用“引用參數(shù)”傳遞函數(shù)參數(shù)
#include <iostream.h> void swap(int& m, int& n) {int temp;temp=m;m=n;n=temp; } main() {int a=5, b=10;cout<<"a="<<a<<" b="<<b<<endl;swap(a, b);cout<<"a="<<a<<" b="<<b<<endl;return 0; }運(yùn)行結(jié)果:
a=5 b=10 a=10 b=5(4) 用引用返回函數(shù)值
函數(shù)可以返回一個(gè)引用,將函數(shù)說明為返回一個(gè)引用的主要目的是:為了將函數(shù)用在賦值運(yùn)算符的左邊。
要以引用返回函數(shù)值,則函數(shù)定義時(shí)要按以下格式:
類型標(biāo)識(shí)符 &函數(shù)名(形參列表及類型說明)
{函數(shù)體}
說明
- 以引用返回函數(shù)值,定義函數(shù)時(shí)需要在函數(shù)名前加&
- 用引用返回一個(gè)函數(shù)值的最大好處是,在內(nèi)存中不產(chǎn)生被返回值的副本。
例1.19 返回引用的函數(shù)
#include <iostream.h> int a[]={1, 3, 5, 7, 9}; int& index(int); // 聲明返回引用的函數(shù) void main() {cout<<index(2)<<endl;index(2)=25; // 將a[2]重新賦值為25cout<<index(2)<<endl; } int& index(int i) {return a[i]; }例1.20 用引用返回函數(shù)的值
#include<iostream.h> int A[10]; int& array(int i); void main() {int i, number;A[0]=0;A[1]=1;cin>>number;for (i=2;i<number;i++){array(i)=array(i-2)+array(i-1);cout<<"array("<<i<<")="<<array(i)<<endl;} } int& array(int i) {return A[i]; }運(yùn)行結(jié)果:
array(2)=1 array(3)=2 array(4)=3 array(5)=5 array(6)=8 array(7)=13 array(8)=21 array(9)=34- 在定義返回引用的函數(shù)時(shí),注意不要返回該函數(shù)內(nèi)的自動(dòng)變量 (局部變量)的引用,由于自動(dòng)變量的生存期僅限于函數(shù)內(nèi)部,當(dāng)函數(shù)返回時(shí),自動(dòng)變量就消失了。
- 傳遞引用給函數(shù)與傳遞指針的效果是一樣的,但使用更簡練。
- 使用引用傳遞函數(shù)的參數(shù),在內(nèi)存中并沒有產(chǎn)生實(shí)參的副本,它是直接對實(shí)參操作;
如何使一個(gè)被調(diào)函數(shù)同時(shí)返回多個(gè)值
由于函數(shù)的返回值是通過函數(shù)體中的return語句完成的,但一個(gè)return語句只能返回一個(gè)值,為此,我們可以采用以下方法:
- (1)利用全局變量的方法:在函數(shù)中把所需數(shù)據(jù)保存在全局變量中。當(dāng)被調(diào)函數(shù)執(zhí)行完畢后在主調(diào)函數(shù)中直接讀取全局變量的值即可。
- (2)使用指針或數(shù)組的方法:指針作為函數(shù)參數(shù)的情況下,可將主調(diào)函數(shù)的某些變量的地址傳遞給被調(diào)函數(shù)。
- (3)利用引用的方法:使用引用傳遞參數(shù),可以在被調(diào)函數(shù)中改變主調(diào)函數(shù)中目標(biāo)變量的值,這種方法實(shí)際上就是可以使被調(diào)函數(shù)返回多個(gè)值。
例 使用引用使函數(shù)返回多個(gè)值
以下定義了可以同時(shí)返回10個(gè)數(shù)中的最大值和最小值的函數(shù)max_min。
#include <iostream.h> void max_min(int *p,int n,int &max,int &min); //聲明函數(shù)max_min void main() {int a[10];int ma,mi;int i;for(i=0;i<10;i++)cin>>a[i];max_min(a,10,ma,mi); //調(diào)用函數(shù)max_mincout<<ma<<mi; } void max_min(int *p,int n,int &max,int &min) //形參max 和min定義成引用 {int i=0;max=*(p+i);min=*(p+i);for(i=1;i<n;i++) {if(max<*(p+i))max=*(p+i); //實(shí)質(zhì)上就是對實(shí)參變量ma賦值if(min>*(p+i))min=*(p+i); //實(shí)質(zhì)上就是對實(shí)參變量mi賦值} }例 以下程序中定義了一個(gè)普通的函數(shù)fn1(它用返回值的方法返回函數(shù)值),另外一個(gè)函數(shù)fn2,它以引用的方法返回函數(shù)值。
#include <iostream.h> float temp; //定義全局變量temp float fn1(float r); //聲明函數(shù)fn1 float &fn2(float r); //聲明函數(shù)fn2 float fn1(float r) //定義函數(shù)fn1,它以返回值的方法返回函數(shù)值 {temp=(float)(r*r*3.14);return temp; } float &fn2(float r) //定義函數(shù)fn2,它以引用方式返回函數(shù)值 {temp=(float)(r*r*3.14);return temp; } void main() //主函數(shù) {float a=fn1(10.0);//第1種情況,系統(tǒng)生成要返回值的副本(即臨時(shí)變量)float &b=fn1(10.0);//第2種情況,可能會(huì)出錯(cuò)(不同C++系統(tǒng)有不同規(guī)定)//不能從被調(diào)函數(shù)中返回一個(gè)臨時(shí)變量或局部變量的引用float c=fn2(10.0); //第3種情況,系統(tǒng)不生成返回值的副本//可以從被調(diào)函數(shù)中返回一個(gè)全局變量的引用float &d=fn2(10.0); //第4種情況,系統(tǒng)不生成返回值的副本//可以從被調(diào)函數(shù)中返回一個(gè)全局變量的引用cout<<a<<c<<d; }一個(gè)返回引用的函數(shù)值作為賦值表達(dá)式的左值
一般情況下,賦值表達(dá)式的左邊只能是變量名,即被賦
值的對象必須是變量,只有變量才能被賦值,常量或表達(dá)式不能被賦值,但如果一個(gè)函數(shù)的返回值是引用時(shí),賦值號的左邊可以是該函數(shù)的調(diào)用。
例2-26 測試用返回引用的函數(shù)值作為賦值表達(dá)式的左值。
#include <iostream.h> int &put(int n); int vals[10]; int error=-1; void main() {put(0)=10; //以put(0)函數(shù)值作為左值, 等價(jià)于vals[0]=10;put(9)=20; //以put(9)函數(shù)值作為左值, 等價(jià)于 vals[9]=10;cout<<vals[0];cout<<vals[9]; } int &put(int n) {if (n>=0 && n<=9 )return vals[n];else{cout<<”subscript error”;return error;} }用const限定引用
聲明方式: const 類型標(biāo)識(shí)符 &引用名=目標(biāo)變量名;
用這種方式聲明的引用,不能通過引用對目標(biāo)變量的值進(jìn)行修改,從而使引用的目標(biāo)成為const,達(dá)到了引用的安全性。
例2-27
#include “iostream.h” double &fn(const double &pd) {static double ad=32;ad+=pd;cout<<pd<<endl;return ad; } void main() {double a=100.0;double &pa=fn(a);cout<<pa<<endl;a=200.0;pa=fn(a);cout<<pa<<endl; }程序運(yùn)行的結(jié)果
100 132 200 332引用總結(jié)
- (1)在引用的使用中,單純給某個(gè)變量取個(gè)別名是毫無意義的,引用的目的主要用于在函數(shù)參數(shù)傳遞中,解決大對象的傳遞效率和空間不如意的問題。
- (2)用引用傳遞函數(shù)的參數(shù),能保證參數(shù)傳遞中不產(chǎn)生副本,提高傳遞的效率,且通過const的使用,保證了引用傳遞的安全性。
- (3)引用與指針的區(qū)別是,指針通過某個(gè)指針變量指向一個(gè)對象后,對它所指向的變量間接操作,程序中使用指針,程序的可讀性差;而引用本身就是目標(biāo)變量的別名,對引用的操作就是對目標(biāo)變量的操作。
課后練習(xí)題目
#include<iostream.h> int &max(int &num1,int &num2); // 返回一個(gè)較大值 int &min(int &num1,int &num2); // 返回一個(gè)較小值 main() {int num1, num2;cout<<"Enter the first number: ";cin>>num1;cout<<"Enter the second number: ";cin>>num2;max(num1,num2)=0;cout<<"\nAfter putting zero in largest, the numbers are";cout<<"\n"<<num1<<" and "<<num2<<"\n";cout<<"\nNow, please enter two more numbers.\n";cout<<"Enter the first number :";cin>>num1;cout<<"Enter the second number:";cin>>num2;min(num1, num2)=0;cout<<"\nAfter putting zero in smallest the numbers are";cout<<"\n"<<num1<<" and "<<num2<<"\n";return 0; } int &max(int &num1,int &num2) {return (num1>num2)?num1:num2; } int &min(int &num1,int &num2) {return (num1<num2)?num1:num2; }轉(zhuǎn)載于:https://www.cnblogs.com/whale90830/p/10488595.html
總結(jié)
以上是生活随笔為你收集整理的OOP_由C到C++的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 我的随笔---高亮规范
- 下一篇: 编解码器之战:AV1、HEVC、VP9和