小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

《C 面向?qū)ο蟪绦蛟O(shè)計(jì)》?千處細(xì)節(jié)、萬(wàn)字總結(jié)(建議收藏)

 山峰云繞 2022-04-18

https://blog.csdn.net/weixin_44368437/article/details/117563488?utm_source=app&app_version=5.3.0&code=app_1562916241&uLinkId=usr1mkqgl919blen 


《C++面向?qū)ο?/a>程序設(shè)計(jì)》?千處細(xì)節(jié)、萬(wàn)字總結(jié)

文章目錄

    • 《C++面向?qū)ο蟪绦蛟O(shè)計(jì)》?千處細(xì)節(jié)、萬(wàn)字總結(jié)
      • 一、面向?qū)ο蟪绦蛟O(shè)計(jì)
      • 二、C++基礎(chǔ)
        • 2.1 C++的產(chǎn)生和特點(diǎn)
        • 2.2 一個(gè)簡(jiǎn)單的C++示例程序
        • 2.3 C++在非面向?qū)ο蠓矫鎸?duì)C語(yǔ)言的擴(kuò)充
          • 輸入和輸出
          • cin
          • const修飾符
          • void型指針
          • 內(nèi)聯(lián)函數(shù)
          • 帶有默認(rèn)參數(shù)值的函數(shù)
          • 函數(shù)重載
          • 作用域標(biāo)識(shí)符'::'
          • 強(qiáng)制類型轉(zhuǎn)換
          • new和delete運(yùn)算符
          • 引用
      • 三、類和對(duì)象(一)
        • 3.1 類的構(gòu)成
        • 3.2 成員函數(shù)的定義
        • 3.3 對(duì)象的定義和使用
        • 3.4 構(gòu)造函數(shù)與析構(gòu)函數(shù)
          • 構(gòu)造函數(shù)
          • 成員初始化列表
          • 帶默認(rèn)參數(shù)的構(gòu)造函數(shù)
          • 析構(gòu)函數(shù)
          • 默認(rèn)的構(gòu)造函數(shù)和析構(gòu)函數(shù)
          • 構(gòu)造函數(shù)的重載
          • 拷貝構(gòu)造函數(shù)
          • 淺拷貝和深拷貝
      • 四、類和對(duì)象(二)
        • 4.1 自引用指針this
        • 4.2 對(duì)象數(shù)組與對(duì)象指針
        • 4.3 string類
        • 4.4 向函數(shù)傳遞對(duì)象
        • 4.5 靜態(tài)成員
        • 4.6 友元
          • 友元函數(shù)
          • 友元類
        • 4.7 類的組合
        • 4.8 共享數(shù)據(jù)的保護(hù)
      • 五、繼承與派生
        • 5.1 繼承與派生的概念
          • 基類成員在派生類中的訪問(wèn)屬性
          • 派生類對(duì)基類成員的訪問(wèn)規(guī)則
        • 5.2 派生類的構(gòu)造函數(shù)和析構(gòu)函數(shù)
        • 5.3 調(diào)整基類成員在派生類中的訪問(wèn)屬性的其他方法
        • 5.4 多繼承
        • 5.5 虛基類
        • 5.6 賦值兼容規(guī)則
      • 六、多態(tài)性與虛函數(shù)
        • 6.1 多態(tài)性概述
        • 6.2 虛函數(shù)
        • 6.3 虛析構(gòu)函數(shù)
        • 6.4 純虛函數(shù)
        • 6.5 抽象類
        • 6.6 示例:利用多態(tài)計(jì)算面積
      • 七、運(yùn)算符重載
        • 7.1 運(yùn)算符重載概述
      • 八、函數(shù)模板與類模板
        • 8.1 模板的概念
        • 8.2 函數(shù)模板
        • 8.3 類模板
      • 九、C++的輸入和輸出
        • 9.1 C++為何建立自己的輸入/輸出系統(tǒng)
        • 9.2 C++的流庫(kù)及其基本結(jié)構(gòu)
          • 用于輸入/輸出的頭文件
          • 用于輸入/輸出的流類
        • 9.3 預(yù)定義的流對(duì)象
        • 9.4 輸入/輸出流的成員函數(shù)
        • 9.5 預(yù)定義類型輸入/輸出的格式控制
        • 9.6 文件的輸入/輸出
        • 9.7 文件的打開與關(guān)閉
        • 9.8 文本文件的讀/寫
        • 9.9 二進(jìn)制文件的讀寫
          • 用get()函數(shù)和put()函數(shù)讀/寫二進(jìn)制文件
          • 用read()函數(shù)和write()函數(shù)讀寫二進(jìn)制文件
          • 檢測(cè)文件結(jié)束
      • 十、異常處理和命名空間
        • 10.1 異常處理
        • 10.2 命名空間和頭文件命名規(guī)則
      • 十一、STL標(biāo)準(zhǔn)模板庫(kù)
        • 11.1 Vector
        • 11.2 list容器
        • 11.3 stack
        • 11.4 queue
        • 11.5 優(yōu)先隊(duì)列priority_queue
        • 11.6 雙端隊(duì)列deque
        • 11.7 set
        • 11.8 map

一、面向?qū)ο蟪绦蛟O(shè)計(jì)

面向?qū)ο蟪绦蛟O(shè)計(jì)(Object-Oriented Programming,OOP)是一種新的程序設(shè)計(jì)范型。程序設(shè)計(jì)范型是指設(shè)計(jì)程序的規(guī)范、模型和風(fēng)格,它是一類程序設(shè)計(jì)語(yǔ)言的基礎(chǔ)。

面向過(guò)程程序設(shè)計(jì)范型是使用較廣泛的面向過(guò)程性語(yǔ)言,其主要特征是:程序由過(guò)程定義過(guò)程調(diào)用組成(簡(jiǎn)單地說(shuō),過(guò)程就是程序執(zhí)行某項(xiàng)操作的一段代碼,函數(shù)就是最常用的過(guò)程)。

面向?qū)ο蟪绦虻幕驹厥菍?duì)象,面向?qū)ο蟪绦虻闹饕Y(jié)構(gòu)特點(diǎn)是:第一,程序一般由類的定義和類的使用兩部分組成;第二,程序中的一切操作都是通過(guò)向?qū)ο蟀l(fā)送消息來(lái)實(shí)現(xiàn)的,對(duì)象接收到消息后,啟動(dòng)有關(guān)方法完成相應(yīng)的操作。

對(duì)象:描述其屬性的數(shù)據(jù)以及對(duì)這些數(shù)據(jù)施加的一組操作封裝在一起構(gòu)成的統(tǒng)一體。對(duì)象可認(rèn)為是數(shù)據(jù)+操作。

:類是具有相同的數(shù)據(jù)和相同的操作的一組對(duì)象的集合。

消息傳遞:對(duì)象之間的交互。

**方法:**對(duì)象實(shí)現(xiàn)的行為稱為方法。

面向?qū)ο蟪绦蛟O(shè)計(jì)的基本特征:抽象、封裝、繼承、多態(tài)。


二、C++基礎(chǔ)

~

2.1 C++的產(chǎn)生和特點(diǎn)

C++是美國(guó)貝爾實(shí)驗(yàn)室的Bjarne Stroustrup博士在C語(yǔ)言的基礎(chǔ)上,彌補(bǔ)了C語(yǔ)言存在的一些缺陷,增加了面向?qū)ο蟮奶卣?,?980年開發(fā)出來(lái)的一種面向過(guò)程性與面向?qū)ο笮韵嘟Y(jié)合的程序設(shè)計(jì)語(yǔ)言。最初他把這種新的語(yǔ)言稱為“含類的C”,到1983年才取名為C++。

相比C語(yǔ)言,C++的主要特點(diǎn)是增加了面向?qū)ο?/strong>機(jī)制。

~

2.2 一個(gè)簡(jiǎn)單的C++示例程序

詳細(xì)創(chuàng)建步驟可參考博客【Visual Studio】 創(chuàng)建C/C++項(xiàng)目

#include <iostream>   //編譯預(yù)處理命令
using namespace std;    //使用命名空間

int add(int a, int b);       //函數(shù)原型說(shuō)明

int main()  //主函數(shù)
{
	int x, y;
	cout << 'Enter two numbers: ' << endl;
	cin >> x;
	cin >> y;
	int sum = add(x, y);
	cout << 'The sum is : ' << sum << '\n';
	return 0;
}

int add(int a, int b) //定義add()函數(shù),函數(shù)值為整型
{
	return a + b;
}

~

2.3 C++在非面向?qū)ο蠓矫鎸?duì)C語(yǔ)言的擴(kuò)充

輸入和輸出
int i;
float f;
cin >> i;
cout << f;
------------
scanf('%d', &i);
printf('%f', f);
----------------
連續(xù)讀入
cin >> a >> b >> c;
cin
  • 在默認(rèn)情況下,運(yùn)算符“>>”將跳過(guò)空白符,然后讀入后面與變量類型相對(duì)應(yīng)的值。因此,給一組變量輸入值時(shí)可用空格符、回車符、制表符將輸入的數(shù)據(jù)間隔開。
  • 當(dāng)輸入字符串(即類型為string的變量)時(shí),提取運(yùn)算符“>>”的作用是跳過(guò)空白字符,讀入后面的非空白字符,直到遇到另一個(gè)空白字符為止,并在串尾放一個(gè)字符串結(jié)束標(biāo)志'\0’。

~

C++允許在代碼塊中的任何地方聲明局部變量。

const修飾符

在C語(yǔ)言中,習(xí)慣使用#define來(lái)定義常量,例如#define PI 3.14,C++提供了一種更靈活、更安全的方式來(lái)定義常量,即使用const修飾符來(lái)定義常量。例如const float PI = 3.14;

const可以與指針一起使用,它們的組合情況復(fù)雜,可歸納為3種:指向常量的指針、常指針和指向常量的常指針。

  • 指向常量的指針:一個(gè)指向常量的指針變量。

    const char* pc = 'abcd';
    該方法不允許改變指針?biāo)傅淖兞?,?    pc[3] = 'x';   是錯(cuò)誤的,
    但是,由于pc是一個(gè)指向常量的普通指針變量,不是常指針,因此可以改變pc所指的地址,例如
        pc = 'ervfs';
    該語(yǔ)句付給了指針另一個(gè)字符串的地址,改變了pc的值。
    
  • 常指針:將指針變量所指的地址聲明為常量

    char* const pc = 'abcd';
    創(chuàng)建一個(gè)常指針,一個(gè)不能移動(dòng)的固定指針,可更改內(nèi)容,如
        pc[3] = 'x';
    但不能改變地址,如
        pc = 'dsff';  不合法
    
  • 指向常量的常指針:這個(gè)指針?biāo)傅牡刂凡荒芨淖?,它所指向的地址中的?nèi)容也不能改變。

    const char* const pc = 'abcd';
    內(nèi)容和地址均不能改變
    

說(shuō)明:

  1. 如果用const定義整型常量,關(guān)鍵字可以省略。即 const in bufsize = 100const bufsize = 100等價(jià);

  2. 常量一旦被建立,在程序的任何地方都不能再更改。

  3. 與#define不同,const定義的常量可以有自己的數(shù)據(jù)類型。

  4. 函數(shù)參數(shù)也可以用const說(shuō)明,用于保證實(shí)參在該函數(shù)內(nèi)不被改動(dòng)。

void型指針

void通常表示無(wú)值,但將void作為指針的類型時(shí),它卻表示不確定的類型。這種void型指針是一種通用型指針,也就是說(shuō)任何類型的指針值都可以賦給void類型的指針變量。

需要指出的是,這里說(shuō)void型指針是通用指針,是指它可以接受任何類型的指針的賦值,但對(duì)已獲值的void型指針,對(duì)它進(jìn)行再處理,如輸出或者傳遞指針值時(shí),則必須再進(jìn)行顯式類型轉(zhuǎn)換,否則會(huì)出錯(cuò)。

    void* pc;
    int i = 123;
    char c = 'a';
    pc = &i;
	cout << pc << endl;         //輸出指針地址006FF730
	cout << *(int*)pc << endl;  //輸出值123
    pc = &c;
	cout << *(char*)pc << endl; //輸出值a
內(nèi)聯(lián)函數(shù)

在函數(shù)名前冠以關(guān)鍵字inline,該函數(shù)就被聲明為內(nèi)聯(lián)函數(shù)。每當(dāng)程序中出現(xiàn)對(duì)該函數(shù)的調(diào)用時(shí),C++編譯器使用函數(shù)體中的代碼插入到調(diào)用該函數(shù)的語(yǔ)句之處,同時(shí)使用實(shí)參代替形參,以便在程序運(yùn)行時(shí)不再進(jìn)行函數(shù)調(diào)用。引入內(nèi)聯(lián)函數(shù)主要是為了消除調(diào)用函數(shù)時(shí)的系統(tǒng)開銷,以提高運(yùn)行速度。

說(shuō)明

  • 內(nèi)聯(lián)函數(shù)在第一次被調(diào)用之前必須進(jìn)行完整的定義,否則編譯器將無(wú)法知道應(yīng)該插入什么代碼
  • 在內(nèi)聯(lián)函數(shù)體內(nèi)一般不能含有復(fù)雜的控制語(yǔ)句,如for語(yǔ)句和switch語(yǔ)句等
  • 使用內(nèi)聯(lián)函數(shù)是一種空間換時(shí)間的措施,若內(nèi)聯(lián)函數(shù)較長(zhǎng),較復(fù)雜且調(diào)用較為頻繁時(shí)不建議使用
#include <iostream>
using namespace std;

inline double circle(double r)  //內(nèi)聯(lián)函數(shù)
{
	double PI = 3.14;
	return PI * r * r;
}

int main() 
{
	for (int i = 1; i <= 3; i++)
		cout << 'r = ' << i << ' area = ' << circle(i) << endl;
	return 0;
}

使用內(nèi)聯(lián)函數(shù)替代宏定義,能消除宏定義的不安全性

帶有默認(rèn)參數(shù)值的函數(shù)

當(dāng)進(jìn)行函數(shù)調(diào)用時(shí),編譯器按從左到右的順序?qū)?shí)參與形參結(jié)合,若未指定足夠的實(shí)參,則編譯器按順序用函數(shù)原型中的默認(rèn)值來(lái)補(bǔ)足所缺少的實(shí)參。

void init(int x = 5, int y = 10);
init (100, 19);   // 100 , 19
init(25);         // 25, 10
init();           // 5, 10
  • 在函數(shù)原型中,所有取默認(rèn)值的參數(shù)都必須出現(xiàn)在不取默認(rèn)值的參數(shù)的右邊。

    int fun(int a, int b, int c = 111);
    
  • 在函數(shù)調(diào)用時(shí),若某個(gè)參數(shù)省略,則其后的參數(shù)皆應(yīng)省略而采取默認(rèn)值。不允許某個(gè)參數(shù)省略后,再給其后的參數(shù)指定參數(shù)值。

函數(shù)重載

在C++中,用戶可以重載函數(shù)。這意味著,在同一作用域內(nèi),只要函數(shù)參數(shù)的類型不同,或者參數(shù)的個(gè)數(shù)不同,或者二者兼而有之,兩個(gè)或者兩個(gè)以上的函數(shù)可以使用相同的函數(shù)名。

#include <iostream>
using namespace std;

int add(int x, int y)
{
	return x + y;
}

double add(double x, double y)
{
	return x + y;
}

int add(int x, int y, int z)
{
	return x + y + z;
}

int main() 
{
	int a = 3, b = 5, c = 7;
	double x = 10.334, y = 8.9003;
	cout << add(a, b) << endl;
	cout << add(x, y) << endl;
	cout << add(a, b, c) << endl;
	return 0;
}

說(shuō)明:

  • 調(diào)用重載函數(shù)時(shí),函數(shù)返回值類型不在參數(shù)匹配檢查之列。因此,若兩個(gè)函數(shù)的參數(shù)個(gè)數(shù)和類型都相同,而只有返回值類型不同,則不允許重載。

    int mul(int x, int y);
    double mul(int x, int y);
    
  • 函數(shù)的重載與帶默認(rèn)值的函數(shù)一起使用時(shí),有可能引起二義性。

    void Drawcircle(int r = 0, int x = 0, int y = 0);
    void Drawcircle(int r);
    Drawcircle(20);
    
  • 在調(diào)用函數(shù)時(shí),如果給出的實(shí)參和形參類型不相符,C++的編譯器會(huì)自動(dòng)地做類型轉(zhuǎn)換工作。如果轉(zhuǎn)換成功,則程序繼續(xù)執(zhí)行,在這種情況下,有可能產(chǎn)生不可識(shí)別的錯(cuò)誤。

    void f_a(int x);
    void f_a(long x);
    f_a(20.83);
    
作用域標(biāo)識(shí)符'::'

通常情況下,如果有兩個(gè)同名變量,一個(gè)是全局的,另一個(gè)是局部的,那么局部變量在其作用域內(nèi)具有較高的優(yōu)先權(quán),它將屏蔽全局變量。

如果希望在局部變量的作用域內(nèi)使用同名的全局變量,可以在該變量前加上“::”,此時(shí)::value代表全局變量value,“::”稱為作用域標(biāo)識(shí)符。

#include <iostream>
using namespace std;

int value;   //定義全局變量value

int main() 
{
	int value;  //定義局部變量value
	value = 100;
	::value = 1000;
	cout << 'local value : ' << value << endl;
	cout << 'global value : ' << ::value << endl;
	return 0;
}
強(qiáng)制類型轉(zhuǎn)換

可用強(qiáng)制類型轉(zhuǎn)換將不同類型的數(shù)據(jù)進(jìn)行轉(zhuǎn)換。例如,要把一個(gè)整型數(shù)(int)轉(zhuǎn)換為雙精度型數(shù)(double),可使用如下的格式:

int i = 10;
double x = (double)i;int i = 10;
double x = double(i);

以上兩種方法C++都能接受,建議使用后一種方法。

new和delete運(yùn)算符

程序運(yùn)行時(shí),計(jì)算機(jī)的內(nèi)存被分為4個(gè)區(qū):程序代碼區(qū)、全局?jǐn)?shù)據(jù)區(qū)、堆和棧。其中,堆可由用戶分配和釋放。C語(yǔ)言中使用函數(shù)malloc()free()來(lái)進(jìn)行動(dòng)態(tài)內(nèi)存管理。C++則提供了運(yùn)算符newdelete來(lái)做同樣的工作,而且后者比前者性能更優(yōu)越,使用更靈活方便。

指針變量名 = new 類型
    int *p;
    p = new int;
delete 指針變量名
    delete p;

下面對(duì)new和delete的使用再做一下幾點(diǎn)說(shuō)明:

  • 用運(yùn)算符new分配的空間,使用結(jié)束后應(yīng)該用也只能用delete顯式地釋放,否則這部分空間將不能回收而變成死空間。

  • 在使用運(yùn)算符new動(dòng)態(tài)分配內(nèi)存時(shí),如果沒有足夠的內(nèi)存滿足分配要求,new將返回空指針NULL)。

  • 使用運(yùn)算符new可以為數(shù)組動(dòng)態(tài)分配內(nèi)存空間,這時(shí)需要在類型后面加上數(shù)組大小。

    指針變量名 = new 類型名[下標(biāo)表達(dá)式];
    int *p = new int[10];
    

    釋放動(dòng)態(tài)分配的數(shù)組存儲(chǔ)區(qū)時(shí),可使用delete運(yùn)算符。

    delete []指針變量名;
    delete p;
    
  • new 可在為簡(jiǎn)單變量分配空間的同時(shí),進(jìn)行初始化

    指針變量名 = new 類型名(初值);
    int *p;
    p = new int(99);
    ···
    delete p;
    
引用

引用reference)是C++對(duì)C的一個(gè)重要擴(kuò)充。變量的引用就是變量的別名,因此引用又稱別名

類型 &引用名 = 已定義的變量名

引用與其所代表的變量共享同一內(nèi)存單元,系統(tǒng)并不為引用另外分配存儲(chǔ)空間。實(shí)際上,編譯系統(tǒng)使引用和其代表的變量具有相同的地址。

#include <iostream>
using namespace std;
int main() 
{
	int i = 10;
	int &j = i;
	cout << 'i = ' << i << ' j = ' << j << endl;
	cout << 'i的地址為 ' << &i << endl;
	cout << 'j的地址為 ' << &j << endl;
	return 0;
}

上面代碼輸出i和j的值相同,地址也相同。

  • 引用并不是一種獨(dú)立的數(shù)據(jù)類型,它必須與某一種類型的變量相聯(lián)系。在聲明引用時(shí),必須立即對(duì)它進(jìn)行初始化,不能聲明完成后再賦值。
  • 為引用提供的初始值,可以是一個(gè)變量或者另一個(gè)引用。
  • 指針是通過(guò)地址間接訪問(wèn)某個(gè)變量,而引用則是通過(guò)別名直接訪問(wèn)某個(gè)變量。

引用作為函數(shù)參數(shù)、使用引用返回函數(shù)值

#include <iostream>
using namespace std;

void swap(int &a, int &b)
{
	int t = a;
	a = b;
	b = t;
}

int a[] = {1, 3, 5, 7, 9};

int& index(int i)
{
	return a[i];
}

int main() 
{
	int a = 5, b = 10;
	//交換數(shù)字a和b
	swap(a, b);
	cout << 'a = ' << a << ' b = ' << b << endl;
	cout << index(2) << endl;   //等價(jià)于輸出元素a[2]的值
	index(2) = 100;             //等價(jià)于將a[2]的值賦為100;
	cout << index(2) << endl;
	
	return 0;
}

對(duì)引用的進(jìn)一步說(shuō)明

  • 不允許建立void類型的引用
  • 不能建立引用的數(shù)組
  • 不能建立引用的引用。不能建立指向引用的指針。引用本身不是一種數(shù)據(jù)類型,所以沒有引用的引用,也沒有引用的指針。
  • 可以將引用的地址賦值給一個(gè)指針,此時(shí)指針指向的是原來(lái)的變量。
  • 可以用const對(duì)引用加以限定,不允許改變?cè)撘玫闹?,但是它不阻止引用所代表的變量的值?/li>

三、類和對(duì)象(一)

~

3.1 類的構(gòu)成

類聲明中的內(nèi)容包括數(shù)據(jù)和函數(shù),分別稱為數(shù)據(jù)成員和成員函數(shù)。按訪問(wèn)權(quán)限劃分,數(shù)據(jù)成員和成員函數(shù)又可分為共有、保護(hù)和私有3種。

class 類名{
    public:
        公有數(shù)據(jù)成員;
        公有成員函數(shù);
    protected:
        保護(hù)數(shù)據(jù)成員;
        保護(hù)成員函數(shù);
    private:
        私有數(shù)據(jù)成員;
        私有成員函數(shù);
};

如成績(jī)類

class Score{
    public:
    void setScore(int m, int f);
    void showScore();
    private:
    int mid_exam;
    int fin_exam;
};
  • 對(duì)一個(gè)具體的類來(lái)講,類聲明格式中的3個(gè)部分并非一定要全有,但至少要有其中的一個(gè)部分。一般情況下,一個(gè)類的數(shù)據(jù)成員應(yīng)該聲明為私有成員,成員函數(shù)聲明為共有成員。這樣,內(nèi)部的數(shù)據(jù)整個(gè)隱蔽在類中,在類的外部根本就無(wú)法看到,使數(shù)據(jù)得到有效的保護(hù),也不會(huì)對(duì)該類以外的其余部分造成影響,程序之間的相互作用就被降低到最小。
  • 類聲明中的關(guān)鍵字private、protected、public可以任意順序出現(xiàn)。
  • 若私有部分處于類的第一部分時(shí),關(guān)鍵字private可以省略。這樣,如果一個(gè)類體中沒有一個(gè)訪問(wèn)權(quán)限關(guān)鍵字,則其中的數(shù)據(jù)成員和成員函數(shù)都默認(rèn)為私有的。
  • 不能在類聲明中給數(shù)據(jù)成員賦初值。

~

3.2 成員函數(shù)的定義

普通成員函數(shù)的定義

在類的聲明中只給出成員函數(shù)的原型,而成員函數(shù)的定義寫在類的外部。這種成員函數(shù)在類外定義的一般形式是:

返回值類型 類名::成員函數(shù)名(參數(shù)表){    函數(shù)體}

例如,表示分?jǐn)?shù)的類Score可聲明如下:

class Score{
public:
	void setScore(int m, int f);
	void showScore();
private:
	int mid_exam;
	int fin_exam;
};

void Score::setScore(int m, int f) 
{
	mid_exam = m;
	fin_exam = f;
}

void Score::showScore()
{
	cout << '期中成績(jī): ' << mid_exam << endl;
	cout << '期末成績(jī):' << fin_exam << endl;
}

內(nèi)聯(lián)成員函數(shù)的定義

  • 隱式聲明:將成員函數(shù)直接定義在類的內(nèi)部
class Score{
public:
	void setScore(int m, int f)
	{
		mid_exam = m;
		fin_exam = f;
	}
	void showScore()
	{
		cout << '期中成績(jī): ' << mid_exam << endl;
		cout << '期末成績(jī):' << fin_exam << endl;
	}
private:
	int mid_exam;
	int fin_exam;
};
  • 顯式聲明:在類聲明中只給出成員函數(shù)的原型,而將成員函數(shù)的定義放在類的外部。
class Score{
public:
	inline void setScore(int m, int f);
	inline void showScore();
private:
	int mid_exam;
	int fin_exam;
};

inline void Score::setScore(int m, int f) 
{
	mid_exam = m;
	fin_exam = f;
}

inline void Score::showScore()
{
	cout << '期中成績(jī): ' << mid_exam << endl;
	cout << '期末成績(jī):' << fin_exam << endl;
}

說(shuō)明:在類中,使用inline定義內(nèi)聯(lián)函數(shù)時(shí),必須將類的聲明和內(nèi)聯(lián)成員函數(shù)的定義都放在同一個(gè)文件(或同一個(gè)頭文件)中,否則編譯時(shí)無(wú)法進(jìn)行代碼置換。

~

3.3 對(duì)象的定義和使用

通常把具有共同屬性和行為的事物所構(gòu)成的集合稱為類。

類的對(duì)象可以看成該類類型的一個(gè)實(shí)例,定義一個(gè)對(duì)象和定義一個(gè)一般變量相似。

對(duì)象的定義

  • 在聲明類的同時(shí),直接定義對(duì)象
class Score{
public:
	void setScore(int m, int f);
	void showScore();
private:
	int mid_exam;
	int fin_exam;
}op1, op2;
  • 聲明了類之后,在使用時(shí)再定義對(duì)象
  Score op1, op2;

對(duì)象中成員的訪問(wèn)

對(duì)象名.數(shù)據(jù)成員名對(duì)象名.成員函數(shù)名[(參數(shù)表)]op1.setScore(89, 99);
op1.showScore();

說(shuō)明

  • 在類的內(nèi)部所有成員之間都可以通過(guò)成員函數(shù)直接訪問(wèn),但是類的外部不能訪問(wèn)對(duì)象的私有成員。

  • 在定義對(duì)象時(shí),若定義的是指向此對(duì)象的指針變量,則訪問(wèn)此對(duì)象的成員時(shí),不能用“.”操作符,而應(yīng)該使用“->“操作符。如

    	Score op, *sc;
    	sc = &op;
    	sc->setScore(99, 100);
    	op.showScore();
    

類的作用域和類成員的訪問(wèn)屬性

私有成員只能被類中的成員函數(shù)訪問(wèn),不能在類的外部,通過(guò)類的對(duì)象進(jìn)行訪問(wèn)。

一般來(lái)說(shuō),公有成員是類的對(duì)外接口,而私有成員是類的內(nèi)部數(shù)據(jù)和內(nèi)部實(shí)現(xiàn),不希望外界訪問(wèn)。將類的成員劃分為不同的訪問(wèn)級(jí)別有兩個(gè)好處:一是信息隱蔽,即實(shí)現(xiàn)封裝,將類的內(nèi)部數(shù)據(jù)與內(nèi)部實(shí)現(xiàn)和外部接口分開,這樣使該類的外部程序不需要了解類的詳細(xì)實(shí)現(xiàn);二是數(shù)據(jù)保護(hù),即將類的重要信息保護(hù)起來(lái),以免其他程序進(jìn)行不恰當(dāng)?shù)男薷摹?/p>

對(duì)象賦值語(yǔ)句

	Score op1, op2;
	op1.setScore(99, 100);
	op2 = op1;
	op2.showScore();

~

3.4 構(gòu)造函數(shù)與析構(gòu)函數(shù)

構(gòu)造函數(shù)

構(gòu)造函數(shù)是一種特殊的成員函數(shù),它主要用于為對(duì)象分配空間,進(jìn)行初始化。構(gòu)造函數(shù)的名字必須與類名相同,而不能由用戶任意命名。它可以有任意類型的參數(shù),但不能具有返回值。它不需要用戶來(lái)調(diào)用,而是在建立對(duì)象時(shí)自動(dòng)執(zhí)行。

class Score{
public:
	Score(int m, int f);  //構(gòu)造函數(shù)
	void setScore(int m, int f);
	void showScore();
private:
	int mid_exam;
	int fin_exam;
};

Score::Score(int m, int f)
{
	mid_exam = m;
	fin_exam = f;
}

在建立對(duì)象的同時(shí),采用構(gòu)造函數(shù)給數(shù)據(jù)成員賦值,通常由以下兩種形式

  • 類名 對(duì)象名[(實(shí)參表)]
    Score op1(99, 100);
    op1.showScore();
    
  • 類名 *指針變量名 = new 類名[(實(shí)參表)]
    Score *p;
    p = new Score(99, 100);
    p->showScore();
    -----------------------
    Score *p = new Score(99, 100);
    p->showScore();
    

說(shuō)明:

  • 構(gòu)造函數(shù)的名字必須與類名相同,否則編譯程序?qū)阉?dāng)做一般的成員函數(shù)來(lái)處理。
  • 構(gòu)造函數(shù)沒有返回值,在定義構(gòu)造函數(shù)時(shí),是不能說(shuō)明它的類型的。
  • 與普通的成員函數(shù)一樣,構(gòu)造函數(shù)的函數(shù)體可以寫在類體內(nèi),也可寫在類體外。
  • 構(gòu)造函數(shù)一般聲明為共有成員,但它不需要也不能像其他成員函數(shù)那樣被顯式地調(diào)用,它是在定義對(duì)象的同時(shí)被自動(dòng)調(diào)用,而且只執(zhí)行一次。
  • 構(gòu)造函數(shù)可以不帶參數(shù)。
成員初始化列表

在聲明類時(shí),對(duì)數(shù)據(jù)成員的初始化工作一般在構(gòu)造函數(shù)中用賦值語(yǔ)句進(jìn)行。此外還可以用成員初始化列表實(shí)現(xiàn)對(duì)數(shù)據(jù)成員的初始化。

類名::構(gòu)造函數(shù)名([參數(shù)表])[:(成員初始化列表)]
{
    //構(gòu)造函數(shù)體
}
class A{
private:
	int x;
	int& rx;
	const double pi;
public:
	A(int v) : x(v), rx(x), pi(3.14)    //成員初始化列表
	{	}
	void print()
	{
		cout << 'x = ' << x << ' rx = ' << rx << ' pi = ' << pi << endl;
	}
};

**說(shuō)明:**類成員是按照它們?cè)陬惱锉宦暶鞯捻樞蜻M(jìn)行初始化的,與它們?cè)诔蓡T初始化列表中列出的順序無(wú)關(guān)。

帶默認(rèn)參數(shù)的構(gòu)造函數(shù)
#include <iostream>
using namespace std;

class Score{
public:
	Score(int m = 0, int f = 0);    //帶默認(rèn)參數(shù)的構(gòu)造函數(shù)
	void setScore(int m, int f);
	void showScore();
private:
	int mid_exam;
	int fin_exam;
};

Score::Score(int m, int f) : mid_exam(m), fin_exam(f)
{
	cout << '構(gòu)造函數(shù)使用中...' << endl;
}

void Score::setScore(int m, int f) 
{
	mid_exam = m;
	fin_exam = f;
}

void Score::showScore()
{
	cout << '期中成績(jī): ' << mid_exam << endl;
	cout << '期末成績(jī):' << fin_exam << endl;
}

int main() 
{
	Score op1(99, 100);
	Score op2(88);
	Score op3;
	op1.showScore();
	op2.showScore();
	op3.showScore();

	return 0;
}
析構(gòu)函數(shù)

析構(gòu)函數(shù)也是一種特殊的成員函數(shù)。它執(zhí)行與構(gòu)造函數(shù)相反的操作,通常用于撤銷對(duì)象時(shí)的一些清理任務(wù),如釋放分配給對(duì)象的內(nèi)存空間等。析構(gòu)函數(shù)有以下一些特點(diǎn):

  1. 析構(gòu)函數(shù)與構(gòu)造函數(shù)名字相同,但它前面必須加一個(gè)波浪號(hào)(~)。
  2. 析構(gòu)函數(shù)沒有參數(shù)和返回值,也不能被重載,因此只有一個(gè)。
  3. 當(dāng)撤銷對(duì)象時(shí),編譯系統(tǒng)會(huì)自動(dòng)調(diào)用析構(gòu)函數(shù)。
class Score{
public:
	Score(int m = 0, int f = 0);
	~Score();       //析構(gòu)函數(shù)
private:
	int mid_exam;
	int fin_exam;
};

Score::Score(int m, int f) : mid_exam(m), fin_exam(f)
{
	cout << '構(gòu)造函數(shù)使用中...' << endl;
}

Score::~Score()
{
	cout << '析構(gòu)函數(shù)使用中...' << endl;
}

**說(shuō)明:**在以下情況中,當(dāng)對(duì)象的生命周期結(jié)束時(shí),析構(gòu)函數(shù)會(huì)被自動(dòng)調(diào)用:

  • 如果定義了一個(gè)全局對(duì)象,則在程序流程離開其作用域時(shí),調(diào)用該全局對(duì)象的析構(gòu)函數(shù)。
  • 如果一個(gè)對(duì)象定義在一個(gè)函數(shù)體內(nèi),則當(dāng)這個(gè)函數(shù)被調(diào)用結(jié)束時(shí),該對(duì)象應(yīng)該被釋放,析構(gòu)函數(shù)被自動(dòng)調(diào)用。
  • 若一個(gè)對(duì)象是使用new運(yùn)算符創(chuàng)建的,在使用delete運(yùn)算符釋放它時(shí),delete會(huì)自動(dòng)調(diào)用析構(gòu)函數(shù)。

如下示例:

#include <iostream>
#include <string>

using namespace std;

class Student{
private:
	char *name;
	char *stu_no;
	float score;
public:
	Student(char *name1, char *stu_no1, float score1);
	~Student();
	void modify(float score1);
	void show();
};

Student::Student(char *name1, char *stu_no1, float score1)
{
	name = new char[strlen(name1) + 1];
	strcpy(name, name1);
	stu_no = new char[strlen(stu_no1) + 1];
	strcpy(stu_no, stu_no1);
	score = score1;
}

Student::~Student() 
{
	delete []name;
	delete []stu_no;
}

void Student::modify(float score1) 
{
	score = score1;
}

void Student::show()
{
	cout << '姓名: ' << name << endl;
	cout << '學(xué)號(hào): ' << stu_no << endl;
	cout << '成績(jī):' << score << endl;
}

int main()
{
	Student stu('雪女', '2020199012', 99);
	stu.modify(100);
	stu.show();

	return 0;
}
默認(rèn)的構(gòu)造函數(shù)和析構(gòu)函數(shù)

如果沒有給類定義構(gòu)造函數(shù),則編譯系統(tǒng)自動(dòng)生成一個(gè)默認(rèn)的構(gòu)造函數(shù)。

說(shuō)明:

  • 對(duì)沒有定義構(gòu)造函數(shù)的類,其公有數(shù)據(jù)成員可以用初始值列表進(jìn)行初始化。

    class A{
    public:
    	char name[10];
    	int no;
    };
    
    A a = {'chen', 23};
    cout << a.name << a.no << endl;
    
  • 只要一個(gè)類定義了一個(gè)構(gòu)造函數(shù)(不一定是無(wú)參構(gòu)造函數(shù)),系統(tǒng)將不再給它提供默認(rèn)的構(gòu)造函數(shù)。

每個(gè)類必須有一個(gè)析構(gòu)函數(shù)。若沒有顯示地為一個(gè)類定義析構(gòu)函數(shù),編譯系統(tǒng)會(huì)自動(dòng)生成一個(gè)默認(rèn)的析構(gòu)函數(shù)。

構(gòu)造函數(shù)的重載
class Score{
public:
	Score(int m, int f);  //構(gòu)造函數(shù)
	Score();
	void setScore(int m, int f);
	void showScore();
private:
	int mid_exam;
	int fin_exam;
};

**注意:**在一個(gè)類中,當(dāng)無(wú)參數(shù)的構(gòu)造函數(shù)和帶默認(rèn)參數(shù)的構(gòu)造函數(shù)重載時(shí),有可能產(chǎn)生二義性。

拷貝構(gòu)造函數(shù)

拷貝構(gòu)造函數(shù)是一種特殊的構(gòu)造函數(shù),其形參是本類對(duì)象的引用??截悩?gòu)造函數(shù)的作用是在建立一個(gè)新對(duì)象時(shí),使用一個(gè)已存在的對(duì)象去初始化這個(gè)新對(duì)象。

拷貝構(gòu)造函數(shù)具有以下特點(diǎn):

  • 因?yàn)榭截悩?gòu)造函數(shù)也是一種構(gòu)造函數(shù),所以其函數(shù)名與類名相同,并且該函數(shù)也沒有返回值。
  • 拷貝構(gòu)造函數(shù)只有一個(gè)參數(shù),并且是同類對(duì)象的引用。
  • 每個(gè)類都必須有一個(gè)拷貝構(gòu)造函數(shù)??梢宰约憾x拷貝構(gòu)造函數(shù),用于按照需要初始化新對(duì)象;如果沒有定義類的拷貝構(gòu)造函數(shù),系統(tǒng)就會(huì)自動(dòng)生成一個(gè)默認(rèn)拷貝構(gòu)造函數(shù),用于復(fù)制出與數(shù)據(jù)成員值完全相同的新對(duì)象。

自定義拷貝構(gòu)造函數(shù)

類名::類名(const 類名 &對(duì)象名) 
{
    拷貝構(gòu)造函數(shù)的函數(shù)體;
}

class Score{
public:
	Score(int m, int f);  //構(gòu)造函數(shù)
	Score();
	Score(const Score &p);  //拷貝構(gòu)造函數(shù)
	~Score();               //析構(gòu)函數(shù)
	void setScore(int m, int f);
	void showScore();
private:
	int mid_exam;
	int fin_exam;
};

Score::Score(int m, int f)
{
	mid_exam = m;
	fin_exam = f;
}

Score::Score(const Score &p)
{
	mid_exam = p.mid_exam;
	fin_exam = p.fin_exam;
}

調(diào)用拷貝構(gòu)造函數(shù)的一般形式為:
    類名 對(duì)象2(對(duì)象1);
    類名 對(duì)象2 = 對(duì)象1;
Score sc1(98, 87);
Score sc2(sc1);    //調(diào)用拷貝構(gòu)造函數(shù)
Score sc3 = sc2;   //調(diào)用拷貝構(gòu)造函數(shù)

調(diào)用拷貝構(gòu)造函數(shù)的三種情況:

  • 當(dāng)用類的一個(gè)對(duì)象去初始化該類的另一個(gè)對(duì)象時(shí);
  • 當(dāng)函數(shù)的形參是類的對(duì)象,調(diào)用函數(shù)進(jìn)行形參和實(shí)參結(jié)合時(shí);
  • 當(dāng)函數(shù)的返回值是對(duì)象,函數(shù)執(zhí)行完成返回調(diào)用者時(shí)。
淺拷貝和深拷貝

淺拷貝,就是由默認(rèn)的拷貝構(gòu)造函數(shù)所實(shí)現(xiàn)的數(shù)據(jù)成員逐一賦值。通常默認(rèn)的拷貝構(gòu)造函數(shù)是能夠勝任此工作的,但若類中含有指針類型的數(shù)據(jù),則這種按數(shù)據(jù)成員逐一賦值的方法會(huì)產(chǎn)生錯(cuò)誤。

class Student{
public:
    Student(char *name1, float score1);
    ~Student();
private:
    char *name;
    float score;
};

如下語(yǔ)句會(huì)產(chǎn)生錯(cuò)誤
Student stu1('白', 89);
Student stu2 = stu1;

上述錯(cuò)誤是因?yàn)閟tu1和stu2所指的內(nèi)存空間相同,在析構(gòu)函數(shù)釋放stu1所指的內(nèi)存后,再釋放stu2所指的內(nèi)存會(huì)發(fā)生錯(cuò)誤,因?yàn)榇藘?nèi)存空間已被釋放。解決方法就是重定義拷貝構(gòu)造函數(shù),為其變量重新生成內(nèi)存空間。

Student::Student(const Student& stu)
{
    name = new char[strlen(stu.name) + 1];
    if (name != 0) {
        strcpy(name, stu.name);
        score = stu.score;
    }
}

四、類和對(duì)象(二)

~

4.1 自引用指針this

this指針保存當(dāng)前對(duì)象的地址,稱為自引用指針

void Sample::copy(Sample& xy)
{
    if (this == &xy) return;
    *this = xy;
}

~

4.2 對(duì)象數(shù)組與對(duì)象指針

對(duì)象數(shù)組

類名 數(shù)組名[下標(biāo)表達(dá)式]
用只有一個(gè)參數(shù)的構(gòu)造函數(shù)給對(duì)象數(shù)組賦值
Exam ob[4] = {89, 97, 79, 88};
用不帶參數(shù)和帶一個(gè)參數(shù)的構(gòu)造函數(shù)給對(duì)象數(shù)組賦值
Exam ob[4] = {89, 90};
用帶有多個(gè)參數(shù)的構(gòu)造函數(shù)給對(duì)象數(shù)組賦值
Score rec[3] = {Score(33, 99), Score(87, 78), Score(99, 100)};

對(duì)象指針

每一個(gè)對(duì)象在初始化后都會(huì)在內(nèi)存中占有一定的空間。因此,既可以通過(guò)對(duì)象名訪問(wèn)對(duì)象,也可以通過(guò)對(duì)象地址來(lái)訪問(wèn)對(duì)象。對(duì)象指針就是用于存放對(duì)象地址的變量。聲明對(duì)象指針的一半語(yǔ)法形式為:類名 *對(duì)象指針名

Score score;
Score *p;
p = &score;
p->成員函數(shù)();

用對(duì)象指針訪問(wèn)對(duì)象數(shù)組

Score score[2];
score[0].setScore(90, 99);
score[1].setScore(67, 89);

Score *p;
p = score;   //將對(duì)象score的地址賦值給p
p->showScore();
p++;    //對(duì)象指針變量加1
p->showSccore();

Score *q;
q =&score[1];   //將第二個(gè)數(shù)組元素的地址賦值給對(duì)象指針變量q

~

4.3 string類

C++支持兩種類型的字符串,第一種是C語(yǔ)言中介紹過(guò)的、包括一個(gè)結(jié)束符’\0’(即以NULL結(jié)束)的字符數(shù)組,標(biāo)準(zhǔn)庫(kù)函數(shù)提供了一組對(duì)其進(jìn)行操作的函數(shù),可以完成許多常用的字符串操作。

C++標(biāo)準(zhǔn)庫(kù)中聲明了一種更方便的字符串類型,即字符串類string,類string提供了對(duì)字符串進(jìn)行處理所需要的操作。使用string類必須在程序的開始包括頭文件string,即要有以下語(yǔ)句:#include <string>

常用的string類運(yùn)算符如下:

=、+、+=、==、!=、<、<=、>、>=、[](訪問(wèn)下標(biāo)對(duì)應(yīng)字符)、>>(輸入)、<<(輸出)
#include <iostream>
#include <string>
using namespace std;

int main()
{
	string str1 = 'ABC';
	string str2('dfdf');
	string str3 = str1 + str2;
	cout<< 'str1 = ' << str1 << '  str2 = ' << str2 << '  str3 = ' << str3 << endl;
	str2 += str2;
	str3 += 'aff';
	cout << 'str2 = ' << str2 << '  str3 = ' << str3 << endl;
	cout << 'str1[1] = ' << str1[1] << '  str1 == str2 ? ' << (str1 == str2) << endl;
	string str = 'ABC';
	cout << 'str == str1 ? ' << (str == str1) << endl;
	return 0;
}

~

4.4 向函數(shù)傳遞對(duì)象

  • 使用對(duì)象作為函數(shù)參數(shù):對(duì)象可以作為參數(shù)傳遞給函數(shù),其方法與傳遞其他類型的數(shù)據(jù)相同。在向函數(shù)傳遞對(duì)象時(shí),是通過(guò)“傳值調(diào)用”的方法傳遞給函數(shù)的。因此,函數(shù)中對(duì)對(duì)象的任何修改均不影響調(diào)用該函數(shù)的對(duì)象(實(shí)參本身)。
  • 使用對(duì)象指針作為函數(shù)參數(shù):對(duì)象指針可以作為函數(shù)的參數(shù),使用對(duì)象指針作為函數(shù)參數(shù)可以實(shí)現(xiàn)傳值調(diào)用,即在函數(shù)調(diào)用時(shí)使實(shí)參對(duì)象和形參對(duì)象指針變量指向同一內(nèi)存地址,在函數(shù)調(diào)用過(guò)程中,形參對(duì)象指針?biāo)傅膶?duì)象值的改變也同樣影響著實(shí)參對(duì)象的值。
  • 使用對(duì)象引用作為函數(shù)參數(shù):在實(shí)際中,使用對(duì)象引用作為函數(shù)參數(shù)非常普遍,大部分程序員喜歡使用對(duì)象引用替代對(duì)象指針作為函數(shù)參數(shù)。因?yàn)槭褂脤?duì)象引用作為函數(shù)參數(shù)不但具有用對(duì)象指針做函數(shù)參數(shù)的優(yōu)點(diǎn),而且用對(duì)象引用作函數(shù)參數(shù)將更簡(jiǎn)單、更直接。
#include <iostream>
using namespace std;

class Point{
public:
	int x;
	int y;
	Point(int x1, int y1) : x(x1), y(y1)  //成員初始化列表
    { }
	int getDistance() 
	{
		return x * x + y * y;
	}
};

void changePoint1(Point point)    //使用對(duì)象作為函數(shù)參數(shù)
{
	point.x += 1;
	point.y -= 1;
}

void changePoint2(Point *point)   //使用對(duì)象指針作為函數(shù)參數(shù)
{
	point->x += 1;
	point->y -= 1;
}

void changePoint3(Point &point)  //使用對(duì)象引用作為函數(shù)參數(shù)
{
	point.x += 1;
	point.y -= 1;
}


int main()
{
	Point point[3] = {Point(1, 1), Point(2, 2), Point(3, 3)};
	Point *p = point;
	changePoint1(*p);
	cout << 'the distance is ' << p[0].getDistance() << endl;
	p++;
	changePoint2(p);
	cout << 'the distance is ' << p->getDistance() << endl;
	changePoint3(point[2]);
	cout << 'the distance is ' << point[2].getDistance() << endl;

	return 0;
}

~

4.5 靜態(tài)成員

靜態(tài)數(shù)據(jù)成員

在一個(gè)類中,若將一個(gè)數(shù)據(jù)成員說(shuō)明為static,則這種成員被稱為靜態(tài)數(shù)據(jù)成員。與一般的數(shù)據(jù)成員不同,無(wú)論建立多少個(gè)類的對(duì)象,都只有一個(gè)靜態(tài)數(shù)據(jù)成員的拷貝。從而實(shí)現(xiàn)了同一個(gè)類的不同對(duì)象之間的數(shù)據(jù)共享。

定義靜態(tài)數(shù)據(jù)成員的格式如下:static 數(shù)據(jù)類型 數(shù)據(jù)成員名;

說(shuō)明:

  1. 靜態(tài)數(shù)據(jù)成員的定義與普通數(shù)據(jù)成員相似,但前面要加上static關(guān)鍵字。

  2. 靜態(tài)數(shù)據(jù)成員的初始化與普通數(shù)據(jù)成員不同。靜態(tài)數(shù)據(jù)成員初始化應(yīng)在類外單獨(dú)進(jìn)行,而且應(yīng)在定義對(duì)象之前進(jìn)行。一般在main()函數(shù)之前、類聲明之后的特殊地帶為它提供定義和初始化。

  3. 靜態(tài)數(shù)據(jù)成員屬于類(準(zhǔn)確地說(shuō),是屬于類中對(duì)象的集合),而不像普通數(shù)據(jù)成員那樣屬于某一對(duì)象,因此,可以使用“類名::”訪問(wèn)靜態(tài)的數(shù)據(jù)成員。格式如下:類名::靜態(tài)數(shù)據(jù)成員名。

  4. 靜態(tài)數(shù)據(jù)成員與靜態(tài)變量一樣,是在編譯時(shí)創(chuàng)建并初始化。它在該類的任何對(duì)象被建立之前就存在。因此,共有的靜態(tài)數(shù)據(jù)成員可以在對(duì)象定義之前被訪問(wèn)。對(duì)象定以后,共有的靜態(tài)數(shù)據(jù)成員也可以通過(guò)對(duì)象進(jìn)行訪問(wèn)。其訪問(wèn)格式如下

    對(duì)象名.靜態(tài)數(shù)據(jù)成員名;
    對(duì)象指針->靜態(tài)數(shù)據(jù)成員名;
    

靜態(tài)成員函數(shù)

在類定義中,前面有static說(shuō)明的成員函數(shù)稱為靜態(tài)成員函數(shù)。靜態(tài)成員函數(shù)屬于整個(gè)類,是該類所有對(duì)象共享的成員函數(shù),而不屬于類中的某個(gè)對(duì)象。靜態(tài)成員函數(shù)的作用不是為了對(duì)象之間的溝通,而是為了處理靜態(tài)數(shù)據(jù)成員。定義靜態(tài)成員函數(shù)的格式如下:

static 返回類型 靜態(tài)成員函數(shù)名(參數(shù)表)

與靜態(tài)數(shù)據(jù)成員類似,調(diào)用公有靜態(tài)成員函數(shù)的一般格式有如下幾種:

類名::靜態(tài)成員函數(shù)名(實(shí)參表);
對(duì)象.靜態(tài)成員函數(shù)名(實(shí)參表);
對(duì)象指針->靜態(tài)成員函數(shù)名(實(shí)參表);

一般而言,靜態(tài)成員函數(shù)不訪問(wèn)類中的非靜態(tài)成員。若確實(shí)需要,靜態(tài)成員函數(shù)只能通過(guò)對(duì)象名(或?qū)ο笾羔?、?duì)象引用)訪問(wèn)該對(duì)象的非靜態(tài)成員。

下面對(duì)靜態(tài)成員函數(shù)的使用再做幾點(diǎn)說(shuō)明:

  1. 一般情況下,靜態(tài)函數(shù)成員主要用來(lái)訪問(wèn)靜態(tài)成員函數(shù)。當(dāng)它與靜態(tài)數(shù)據(jù)成員一起使用時(shí),達(dá)到了對(duì)同一個(gè)類中對(duì)象之間共享數(shù)據(jù)的目的。
  2. 私有靜態(tài)成員函數(shù)不能被類外部的函數(shù)和對(duì)象訪問(wèn)。
  3. 使用靜態(tài)成員函數(shù)的一個(gè)原因是,可以用它在建立任何對(duì)象之前調(diào)用靜態(tài)成員函數(shù),以處理靜態(tài)數(shù)據(jù)成員,這是普通成員函數(shù)不能實(shí)現(xiàn)的功能
  4. 編譯系統(tǒng)將靜態(tài)成員函數(shù)限定為內(nèi)部連接,也就是說(shuō),與現(xiàn)行文件相連接的其他文件中的同名函數(shù)不會(huì)與該函數(shù)發(fā)生沖突,維護(hù)了該函數(shù)使用的安全性,這是使用靜態(tài)成員函數(shù)的另一個(gè)原因。
  5. 靜態(tài)成員函數(shù)是類的一部分,而不是對(duì)象的一部分。如果要在類外調(diào)用公有的靜態(tài)成員函數(shù),使用如下格式較好:類名::靜態(tài)成員函數(shù)名()
#include <iostream>
using namespace std;

class Score{
private:
	int mid_exam;
	int fin_exam;
	static int count;     //靜態(tài)數(shù)據(jù)成員,用于統(tǒng)計(jì)學(xué)生人數(shù)
	static float sum;     //靜態(tài)數(shù)據(jù)成員,用于統(tǒng)計(jì)期末累加成績(jī)
	static float ave;     //靜態(tài)數(shù)據(jù)成員,用于統(tǒng)計(jì)期末平均成績(jī)
public:
	Score(int m, int f);
	~Score();
	static void show_count_sum_ave();   //靜態(tài)成員函數(shù)
};

Score::Score(int m, int f)
{
	mid_exam = m;
	fin_exam = f;
	++count;
	sum += fin_exam;
	ave = sum / count;
}

Score::~Score()
{

}

/*** 靜態(tài)成員初始化 ***/
int Score::count = 0;
float Score::sum = 0.0;
float Score::ave = 0.0;

void Score::show_count_sum_ave()
{
	cout << '學(xué)生人數(shù): ' << count << endl;
	cout << '期末累加成績(jī): ' << sum << endl;
	cout << '期末平均成績(jī): ' << ave << endl;
}

int main()
{
	Score sco[3] = {Score(90, 89), Score(78, 99), Score(89, 88)};
	sco[2].show_count_sum_ave();
	Score::show_count_sum_ave();

	return 0;
}

~

4.6 友元

類的主要特點(diǎn)之一是數(shù)據(jù)隱藏和封裝,即類的私有成員(或保護(hù)成員)只能在類定義的范圍內(nèi)使用,也就是說(shuō)私有成員只能通過(guò)它的成員函數(shù)來(lái)訪問(wèn)。但是,有時(shí)為了訪問(wèn)類的私有成員而需要在程序中多次調(diào)用成員函數(shù),這樣會(huì)因?yàn)轭l繁調(diào)用帶來(lái)較大的時(shí)間和空間開銷,從而降低程序的運(yùn)行效率。為此,C++提供了友元來(lái)對(duì)私有或保護(hù)成員進(jìn)行訪問(wèn)。友元包括友元函數(shù)和友元類。

友元函數(shù)

友元函數(shù)既可以是不屬于任何類的非成員函數(shù),也可以是另一個(gè)類的成員函數(shù)。友元函數(shù)不是當(dāng)前類的成員函數(shù),但它可以訪問(wèn)該類的所有成員,包括私有成員、保護(hù)成員和公有成員。

在類中聲明友元函數(shù)時(shí),需要在其函數(shù)名前加上關(guān)鍵字friend。此聲明可以放在公有部分,也可以放在保護(hù)部分和私有部分。友元函數(shù)可以定義在類內(nèi)部,也可以定義在類外部。

1、將非成員函數(shù)聲明為友元函數(shù)

#include <iostream>
using namespace std;
class Score{
private:
	int mid_exam;
	int fin_exam;
public:
	Score(int m, int f);
	void showScore();
	friend int getScore(Score &ob);
};

Score::Score(int m, int f)
{
	mid_exam = m;
	fin_exam = f;
}

int getScore(Score &ob)
{
	return (int)(0.3 * ob.mid_exam + 0.7 * ob.fin_exam);
}

int main()
{
	Score score(98, 78);
	cout << '成績(jī)?yōu)? ' << getScore(score) << endl;

	return 0;
}

說(shuō)明:

  1. 友元函數(shù)雖然可以訪問(wèn)類對(duì)象的私有成員,但他畢竟不是成員函數(shù)。因此,在類的外部定義友元函數(shù)時(shí),不必像成員函數(shù)那樣,在函數(shù)名前加上“類名::”。
  2. 因?yàn)橛言瘮?shù)不是類的成員,所以它不能直接訪問(wèn)對(duì)象的數(shù)據(jù)成員,也不能通過(guò)this指針訪問(wèn)對(duì)象的數(shù)據(jù)成員,它必須通過(guò)作為入口參數(shù)傳遞進(jìn)來(lái)的對(duì)象名(或?qū)ο笾羔?、?duì)象引用)來(lái)訪問(wèn)該對(duì)象的數(shù)據(jù)成員。
  3. 友元函數(shù)提供了不同類的成員函數(shù)之間、類的成員函數(shù)與一般函數(shù)之間進(jìn)行數(shù)據(jù)共享的機(jī)制。尤其當(dāng)一個(gè)函數(shù)需要訪問(wèn)多個(gè)類時(shí),友元函數(shù)非常有用,普通的成員函數(shù)只能訪問(wèn)其所屬的類,但是多個(gè)類的友元函數(shù)能夠訪問(wèn)相關(guān)的所有類的數(shù)據(jù)。

例子:一個(gè)函數(shù)同時(shí)定義為兩個(gè)類的友元函數(shù)

#include <iostream>
#include <string>
using namespace std;

class Score;    //對(duì)Score類的提前引用說(shuō)明
class Student{
private:
	string name;
	int number;
public:
	Student(string na, int nu) {
		name = na;
		number = nu;
	}
	friend void show(Score &sc, Student &st);
};

class Score{
private:
	int mid_exam;
	int fin_exam;
public:
	Score(int m, int f) {
		mid_exam = m;
		fin_exam = f;
	}
	friend void show(Score &sc, Student &st);
};

void show(Score &sc, Student &st) {
	cout << '姓名:' << st.name << '  學(xué)號(hào):' << st.number << endl;
	cout << '期中成績(jī):' << sc.mid_exam << '  期末成績(jī):' << sc.fin_exam << endl;
}

int main() {
	Score sc(89, 99);
	Student st('白', 12467);
	show(sc, st);

	return 0;
}

2、將成員函數(shù)聲明為友元函數(shù)

一個(gè)類的成員函數(shù)可以作為另一個(gè)類的友元,它是友元函數(shù)中的一種,稱為友元成員函數(shù)。友元成員函數(shù)不僅可以訪問(wèn)自己所在類對(duì)象中的私有成員和公有成員,還可以訪問(wèn)friend聲明語(yǔ)句所在類對(duì)象中的所有成員,這樣能使兩個(gè)類相互合作、協(xié)調(diào)工作,完成某一任務(wù)。

#include <iostream>
#include <string>
using namespace std;

class Score;    //對(duì)Score類的提前引用說(shuō)明
class Student{
private:
	string name;
	int number;
public:
	Student(string na, int nu) {
		name = na;
		number = nu;
	}
	void show(Score &sc);
};

class Score{
private:
	int mid_exam;
	int fin_exam;
public:
	Score(int m, int f) {
		mid_exam = m;
		fin_exam = f;
	}
	friend void Student::show(Score &sc);
};

void Student::show(Score &sc) {
	cout << '姓名:' << name << '  學(xué)號(hào):' << number << endl;
	cout << '期中成績(jī):' << sc.mid_exam << '  期末成績(jī):' << sc.fin_exam << endl;
}

int main() {
	Score sc(89, 99);
	Student st('白', 12467);
	st.show(sc);

	return 0;
}

說(shuō)明:

  1. 一個(gè)類的成員函數(shù)作為另一個(gè)類的友元函數(shù)時(shí),必須先定義這個(gè)類。并且在聲明友元函數(shù)時(shí),需要加上成員函數(shù)所在類的類名;
友元類

可以將一個(gè)類聲明為另一個(gè)類的友元

class Y{
    ···
};
class X{
    friend Y;    //聲明類Y為類X的友元類
};

當(dāng)一個(gè)類被說(shuō)明為另一個(gè)類的友元類時(shí),它所有的成員函數(shù)都成為另一個(gè)類的友元函數(shù),這就意味著作為友元類中的所有成員函數(shù)都可以訪問(wèn)另一個(gè)類中的所有成員。

友元關(guān)系不具有交換性傳遞性

~

4.7 類的組合

在一個(gè)類中內(nèi)嵌另一個(gè)類的對(duì)象作為數(shù)據(jù)成員,稱為類的組合。該內(nèi)嵌對(duì)象稱為對(duì)象成員,又稱為子對(duì)象

class Y{
    ···
};
class X{
    Y y;
    ···
};

~

4.8 共享數(shù)據(jù)的保護(hù)

常類型的引入就是為了既保護(hù)數(shù)據(jù)共享又防止數(shù)據(jù)被改動(dòng)。常類型是指使用類型修飾符const說(shuō)明的類型,常類型的變量或?qū)ο蟪蓡T的值在程序運(yùn)行期間是不可改變的。

常引用

如果在說(shuō)明引用時(shí)用const修飾,則被說(shuō)明的引用為常引用。常引用所引用的對(duì)象不能被更新。如果用常引用做形參,便不會(huì)產(chǎn)生對(duì)實(shí)參的不希望的更改。

const 類型& 引用名

int a = 5;
const int& b = a;
此時(shí)再對(duì)b賦值是非法的。
---------------------------
int add(const int& m, const int& n) {
    return m + n;
}
在此函數(shù)中對(duì)變量m和變量n更新時(shí)非法的

常對(duì)象

如果在說(shuō)明對(duì)象時(shí)用const修飾,則被說(shuō)明的對(duì)象為常對(duì)象。常對(duì)象中的數(shù)據(jù)成員為常量且必須要有初值。

類名 const 對(duì)象名[(參數(shù)表)];

const Date date(2021, 5, 31);

常對(duì)象成員

1、常數(shù)據(jù)成員

類的數(shù)據(jù)成員可以是常量或常引用,使用const說(shuō)明的數(shù)據(jù)成員稱為常數(shù)據(jù)成員。如果在一個(gè)類中說(shuō)明了常數(shù)據(jù)成員,那么構(gòu)造函數(shù)就只能通過(guò)成員初始化列表對(duì)該數(shù)據(jù)成員進(jìn)行初始化,而任何其他函數(shù)都不能對(duì)該成員賦值。

class Date{
private:
	int year;
	int month;
	int day;
public:
	Date(int y, int m, int d) : year(y), month(m), day(d) {

	}
};

一旦某對(duì)象的常數(shù)據(jù)成員初始化后,該數(shù)據(jù)成員的值是不能改變的。

2、常成員函數(shù)

類型 函數(shù)名(參數(shù)表) const;

const是函數(shù)類型的一個(gè)組成部分,因此在聲明函數(shù)和定義函數(shù)時(shí)都要有關(guān)鍵字const。在調(diào)用時(shí)不必加const。

class Date{
private:
	int year;
	int month;
	int day;
public:
	Date(int y, int m, int d) : year(y), month(m), day(d){

	}
	void showDate();
	void showDate() const;
};

void Date::showDate() {
	//···
}

void Date::showDate() const {
	//···
}

關(guān)鍵字const可以被用于對(duì)重載函數(shù)進(jìn)行區(qū)分。

說(shuō)明:

  1. 常成員函數(shù)可以訪問(wèn)常數(shù)據(jù)成員,也可以訪問(wèn)普通數(shù)據(jù)成員。
  2. 常對(duì)象只能調(diào)用它的常成員對(duì)象,而不能調(diào)用普通成員函數(shù)。常成員函數(shù)是常對(duì)象唯一的對(duì)外接口。
  3. 常對(duì)象函數(shù)不能更新對(duì)象的數(shù)據(jù)成員,也不能調(diào)用該類的普通成員函數(shù),這就保證了在常成員函數(shù)中絕不會(huì)更新數(shù)據(jù)成員的值。

五、繼承與派生

繼承可以在已有類的基礎(chǔ)上創(chuàng)建新的類,新類可以從一個(gè)或多個(gè)已有類中繼承成員函數(shù)和數(shù)據(jù)成員,而且可以重新定義或加進(jìn)新的數(shù)據(jù)和函數(shù),從而形成類的層次或等級(jí)。其中,已有類稱為基類父類,在它基礎(chǔ)上建立的新類稱為派生類子類

~

5.1 繼承與派生的概念

類的繼承是新的類從已有類那里得到已有的特性。從另一個(gè)角度來(lái)看這個(gè)問(wèn)題,從已有類產(chǎn)生新類的過(guò)程就是類的派生。類的繼承和派生機(jī)制較好地解決了代碼重用的問(wèn)題。

關(guān)于基類和派生類的關(guān)系,可以表述為:派生類是基類的具體化,而基類則是派生類的抽象。

使用繼承的案例如下:

#include <iostream>
#include <string>
using namespace std;

class Person{
private:
	string name;
	string id_number;
	int age;
public:
	Person(string name1, string id_number1, int age1) {
		name = name1;
		id_number = id_number1;
		age = age1;
	}
	~Person() {

	}
	void show() {
		cout << '姓名: ' << name << '  身份證號(hào): ' << id_number << ' 年齡: ' << age << endl;
	}
};

class Student:public Person{
private:
	int credit;
public:
	Student(string name1, string id_number1, int age1, int credit1):Person(name1, id_number1, credit1) {
		credit = credit1;
	}
	~Student() {

	}
	void show() {
		Person::show();
		cout << '學(xué)分: ' << credit << endl;
	}
};

int main() {
	Student stu('白', '110103**********23', 12, 123);
	stu.show();

	return 0;
}

從已有類派生出新類時(shí),可以在派生類內(nèi)完成以下幾種功能:

  1. 可以增加新的數(shù)據(jù)成員和成員函數(shù)
  2. 可以對(duì)基類的成員進(jìn)行重定義
  3. 可以改變基類成員在派生類中的訪問(wèn)屬性
基類成員在派生類中的訪問(wèn)屬性

派生類可以繼承基類中除了構(gòu)造函數(shù)與析構(gòu)函數(shù)之外的成員,但是這些成員的訪問(wèn)屬性在派生過(guò)程中是可以調(diào)整的。從基類繼承來(lái)的成員在派生類中的訪問(wèn)屬性也有所不同。

基類中的成員繼承方式基類在派生類中的訪問(wèn)屬性
privatepublic|protected|private不可直接訪問(wèn)
publicpublic|protected|privatepublic|protected|private
protectedpublic|protected|privateprotected|protected|private
派生類對(duì)基類成員的訪問(wèn)規(guī)則

基類的成員可以有public、protected、private3中訪問(wèn)屬性,基類的成員函數(shù)可以訪問(wèn)基類中其他成員,但是在類外通過(guò)基類的對(duì)象,就只能訪問(wèn)該基類的公有成員。同樣,派生類的成員也可以有public、protected、private3種訪問(wèn)屬性,派生類的成員函數(shù)可以訪問(wèn)派生類中自己增加的成員,但是在派生類外通過(guò)派生類的對(duì)象,就只能訪問(wèn)該派生類的公有成員。

派生類對(duì)基類成員的訪問(wèn)形式主要有以下兩種:

  • 內(nèi)部訪問(wèn):由派生類中新增的成員函數(shù)對(duì)基類繼承來(lái)的成員的訪問(wèn)。
  • 對(duì)象訪問(wèn):在派生類外部,通過(guò)派生類的對(duì)象對(duì)從基類繼承來(lái)的成員的訪問(wèn)。

~

5.2 派生類的構(gòu)造函數(shù)和析構(gòu)函數(shù)

構(gòu)造函數(shù)的主要作用是對(duì)數(shù)據(jù)進(jìn)行初始化。在派生類中,如果對(duì)派生類新增的成員進(jìn)行初始化,就需要加入派生類的構(gòu)造函數(shù)。與此同時(shí),對(duì)所有從基類繼承下來(lái)的成員的初始化工作,還是由基類的構(gòu)造函數(shù)完成,但是基類的構(gòu)造函數(shù)和析構(gòu)函數(shù)不能被繼承,因此必須在派生類的構(gòu)造函數(shù)中對(duì)基類的構(gòu)造函數(shù)所需要的參數(shù)進(jìn)行設(shè)置。同樣,對(duì)撤銷派生類對(duì)象的掃尾、清理工作也需要加入新的析構(gòu)函數(shù)來(lái)完成。

調(diào)用順序

#include <iostream>
#include <string>
using namespace std;

class A{
public:
	A() {
		cout << 'A類對(duì)象構(gòu)造中...' << endl;
	}
	~A() {
		cout << '析構(gòu)A類對(duì)象...' << endl;
	}
};

class B : public A{
public:
	B() {
		cout << 'B類對(duì)象構(gòu)造中...' << endl;
	}
	~B(){
		cout << '析構(gòu)B類對(duì)象...' << endl;
	}
};

int main() {
	B b;
	return 0;
}

代碼運(yùn)行結(jié)果如下:

A類對(duì)象構(gòu)造中...
B類對(duì)象構(gòu)造中...
析構(gòu)B類對(duì)象...
析構(gòu)A類對(duì)象...

可見:構(gòu)造函數(shù)的調(diào)用嚴(yán)格地按照先調(diào)用基類的構(gòu)造函數(shù),后調(diào)用派生類的構(gòu)造函數(shù)的順序執(zhí)行。析構(gòu)函數(shù)的調(diào)用順序與構(gòu)造函數(shù)的調(diào)用順序正好相反,先調(diào)用派生類的析構(gòu)函數(shù),后調(diào)用基類的析構(gòu)函數(shù)。

派生類構(gòu)造函數(shù)和析構(gòu)函數(shù)的構(gòu)造規(guī)則

派生類構(gòu)造函數(shù)的一般格式為:
派生類名(參數(shù)總表):基類名(參數(shù)表) {
    派生類新增數(shù)據(jù)成員的初始化語(yǔ)句
}
-----------------------------------------------------------------
含有子對(duì)象的派生類的構(gòu)造函數(shù):
派生類名(參數(shù)總表):基類名(參數(shù)表0),子對(duì)象名1(參數(shù)表1),...,子對(duì)象名n(參數(shù)表n)
{
    派生類新增成員的初始化語(yǔ)句
}

在定義派生類對(duì)象時(shí),構(gòu)造函數(shù)的調(diào)用順序如下:

調(diào)用基類的構(gòu)造函數(shù),對(duì)基類數(shù)據(jù)成員初始化。

調(diào)用子對(duì)象的構(gòu)造函數(shù),對(duì)子對(duì)象的數(shù)據(jù)成員初始化。

調(diào)用派生類的構(gòu)造函數(shù)體,對(duì)派生類的數(shù)據(jù)成員初始化。

說(shuō)明:

  1. 當(dāng)基類構(gòu)造函數(shù)不帶參數(shù)時(shí),派生類不一定需要定義構(gòu)造函數(shù);然而當(dāng)基類的構(gòu)造函數(shù)哪怕只帶有一個(gè)參數(shù),它所有的派生類都必須定義構(gòu)造函數(shù),甚至所定義的派生類構(gòu)造函數(shù)的函數(shù)體可能為空,它僅僅起參數(shù)的傳遞作用。
  2. 若基類使用默認(rèn)構(gòu)造函數(shù)或不帶參數(shù)的構(gòu)造函數(shù),則在派生類中定義構(gòu)造函數(shù)時(shí)可略去“:基類構(gòu)造函數(shù)名(參數(shù)表)”,此時(shí)若派生類也不需要構(gòu)造函數(shù),則可不定義構(gòu)造函數(shù)。
  3. 如果派生類的基類也是一個(gè)派生類,每個(gè)派生類只需負(fù)責(zé)其直接基類數(shù)據(jù)成員的初始化,依次上溯。

~

5.3 調(diào)整基類成員在派生類中的訪問(wèn)屬性的其他方法

派生類可以聲明與基類成員同名的成員。在沒有虛函數(shù)的情況下,如果在派生類中定義了與基類成員同名的成員,則稱派生類成員覆蓋了基類的同名成員,在派生類中使用這個(gè)名字意味著訪問(wèn)在派生類中聲明的成員。為了在派生類中使用與基類同名的成員,必須在該成員名之前加上基類名和作用域標(biāo)識(shí)符“::”,即

基類名::成員名

訪問(wèn)聲明

訪問(wèn)聲明的方法就是把基類的保護(hù)成員或共有成員直接寫在私有派生類定義式中的同名段中,同時(shí)給成員名前冠以基類名和作用域標(biāo)識(shí)符“::”。利用這種方法,該成員就成為派生類的保護(hù)成員或共有成員了。

class B:private A{
private:
    int y;
public:
    B(int x1, int y1) : A(x1) {
        y = y1;
    }
    A::show;               //訪問(wèn)聲明
};

訪問(wèn)聲明在使用時(shí)應(yīng)注意以下幾點(diǎn):

  1. 數(shù)據(jù)成員也可以使用訪問(wèn)聲明。
  2. 訪問(wèn)聲明中只含不帶類型和參數(shù)的函數(shù)名或變量名。
  3. 訪問(wèn)聲明不能改變成員在基類中的訪問(wèn)屬性。
  4. 對(duì)于基類的重載函數(shù)名,訪問(wèn)聲明將對(duì)基類中所有同名函數(shù)其起作用。

~

5.4 多繼承

聲明多繼承派生類的一般形式如下:

class 派生類名:繼承方式1 基類名1,...,繼承方式n 基類名n {
    派生類新增的數(shù)據(jù)成員和成員函數(shù)
};
默認(rèn)的繼承方式是private

多繼承派生類的構(gòu)造函數(shù)與析構(gòu)函數(shù):

與單繼承派生類構(gòu)造函數(shù)相同,多重繼承派生類構(gòu)造函數(shù)必須同時(shí)負(fù)責(zé)該派生類所有基類構(gòu)造函數(shù)的調(diào)用。

多繼承構(gòu)造函數(shù)的調(diào)用順序與單繼承構(gòu)造函數(shù)的調(diào)用順序相同,也是遵循先調(diào)用基類的構(gòu)造函數(shù),再調(diào)用對(duì)象成員的構(gòu)造函數(shù),最后調(diào)用派生類構(gòu)造函數(shù)的原則。析構(gòu)函數(shù)的調(diào)用與之相反。

~

5.5 虛基類

虛基類的作用:如果一個(gè)類有多個(gè)直接基類,而這些直接基類又有一個(gè)共同的基類,則在最低層的派生類中會(huì)保留這個(gè)間接的共同基類數(shù)據(jù)成員的多份同名成員。在訪問(wèn)這些同名成員時(shí),必須在派生類對(duì)象名后增加直接基類名,使其唯一地標(biāo)識(shí)一個(gè)成員,以免產(chǎn)生二義性。

#include <iostream>
#include <string>
using namespace std;

class Base{
protected:
	int a;
public:
	Base(){
		a = 5;
		cout << 'Base a = ' << a << endl;
	}
};

class Base1: public Base{
public:
	Base1() {
		a = a + 10;
		cout << 'Base1 a = ' << a << endl;
	}
};

class Base2: public Base{
public:
	Base2() {
		a = a + 20;
		cout << 'Base2 a = ' << a << endl;
	}
};

class Derived: public Base1, public Base2{
public:
	Derived() {
		cout << 'Base1::a = ' << Base1::a << endl;
		cout << 'Base2::a = ' << Base2::a << endl;
	}
};

int main() {
	Derived obj;
	return 0;
}

代碼執(zhí)行結(jié)果如下

Base a = 5
Base1 a = 15
Base a = 5
Base2 a = 25
Base1::a = 15
Base2::a = 25

虛基類的聲明:

不難理解,如果在上列中類base只存在一個(gè)拷貝(即只有一個(gè)數(shù)據(jù)成員a),那么對(duì)a的訪問(wèn)就不會(huì)產(chǎn)生二義性。在C++中,可以通過(guò)將這個(gè)公共的基類聲明為虛基類來(lái)解決這個(gè)問(wèn)題。這就要求從類base派生新類時(shí),使用關(guān)鍵字virtual將base聲明為虛基類。

聲明虛基類的語(yǔ)法形式如下:

class 派生類:virtual 繼承方式 類名{
    ·····
};

上述代碼修改如下:

class Base1:virtual public Base{
public:
	Base1() {
		a = a + 10;
		cout << 'Base1 a = ' << a << endl;
	}
};

class Base2:virtual public Base{
public:
	Base2() {
		a = a + 20;
		cout << 'Base2 a = ' << a << endl;
	}
};

運(yùn)行結(jié)果如下:

Base a = 5
Base1 a = 15
Base2 a = 35
Base1::a = 35
Base2::a = 35

虛基類的初始化:

虛基類的初始化與一般的多繼承的初始化在語(yǔ)法上是一樣的,但構(gòu)造函數(shù)的調(diào)用順序不同。在使用虛基類機(jī)制時(shí)應(yīng)該注意以下幾點(diǎn):

  1. 如果在虛基類中定義有帶形參的構(gòu)造函數(shù),并且沒有定義默認(rèn)形式的構(gòu)造函數(shù),則整個(gè)繼承結(jié)構(gòu)中,所有直接或間接的派生類都必須在構(gòu)造函數(shù)的成員初始化列表中列出對(duì)虛基類構(gòu)造函數(shù)的調(diào)用,以初始化在虛基類中定義的數(shù)據(jù)成員。
  2. 建立一個(gè)對(duì)象時(shí),如果這個(gè)對(duì)象中含有從虛基類繼承來(lái)的成員,則虛基類的成員是由最遠(yuǎn)派生類的構(gòu)造函數(shù)通過(guò)調(diào)用虛基類的構(gòu)造函數(shù)進(jìn)行初始化的。該派生類的其他基類對(duì)虛基類構(gòu)造函數(shù)的調(diào)用都被自動(dòng)忽略。
  3. 若同一層次中同時(shí)包含虛基類和非虛基類,應(yīng)先調(diào)用虛基類的構(gòu)造函數(shù),再調(diào)用非虛基類的構(gòu)造函數(shù),最后調(diào)用派生類構(gòu)造函數(shù)。
  4. 對(duì)于多個(gè)虛基類,構(gòu)造函數(shù)的執(zhí)行順序仍然是先左后右,自上而下。
  5. 若虛基類由非虛基類派生而來(lái),則仍然先調(diào)用基類構(gòu)造函數(shù),再調(diào)用派生類的構(gòu)造函數(shù)。

~

5.6 賦值兼容規(guī)則

在一定條件下,不同類型的數(shù)據(jù)之間可以進(jìn)行類型轉(zhuǎn)換,如可以將整型數(shù)據(jù)賦值給雙精度型變量。在賦值之前,先把整型數(shù)據(jù)轉(zhuǎn)換成雙精度數(shù)據(jù),然后再把它賦給雙精度變量。這種不同數(shù)據(jù)類型之間的自動(dòng)轉(zhuǎn)換和賦值,稱為賦值兼容。在基類和派生類對(duì)象之間也存有賦值兼容關(guān)系,基類和派生類對(duì)象之間的賦值兼容規(guī)則是指在需要基類對(duì)象的任何地方,都可以用子類的對(duì)象代替。

例如,下面聲明的兩個(gè)類:

class Base{
    ·····
};
class Derived: public Base{
    ·····
};

根據(jù)賦值兼容規(guī)則,在基類Base的對(duì)象可以使用的任何地方,都可以使用派生類Derived的對(duì)象來(lái)代替,但只能使用從基類繼承來(lái)的成員。具體的表現(xiàn)在以下幾個(gè)方面:

  • 派生類對(duì)象可以賦值給基類對(duì)象,即用派生類對(duì)象中從基類繼承來(lái)的數(shù)據(jù)成員,逐個(gè)賦值給基類對(duì)象的數(shù)據(jù)成員。

    Base b;
    Derived d;
    b = d;
    
  • 派生類對(duì)象可以初始化基類對(duì)象的引用。

    Derived d;
    Base &br = d;
    
  • 派生類對(duì)象的地址可以賦值給指向基類對(duì)象的指針。

    Derived d;
    Base *bp = &d;
    

六、多態(tài)性與虛函數(shù)

多態(tài)性是面向?qū)ο蟪绦蛟O(shè)計(jì)的重要特征之一。多態(tài)性機(jī)制不僅增加了面向?qū)ο筌浖到y(tǒng)的靈活性,進(jìn)一步減少了冗余信息,而且顯著提高了軟件的可重用性和可擴(kuò)充性。多態(tài)性的應(yīng)用可以使編程顯得更簡(jiǎn)潔便利,它為程序的模塊化設(shè)計(jì)又提供了一種手段。

~

6.1 多態(tài)性概述

所謂多態(tài)性就是不同對(duì)象收到相同的消息時(shí),產(chǎn)生不同的動(dòng)作。這樣,就可以用同樣的接口訪問(wèn)不同功能的函數(shù),從而實(shí)現(xiàn)“一個(gè)接口,多種方法”。

從實(shí)現(xiàn)的角度來(lái)講,多態(tài)可以劃分為兩類:編譯時(shí)的多態(tài)運(yùn)行時(shí)的多態(tài)。在C++中,多態(tài)的實(shí)現(xiàn)和連編這一概念有關(guān)。所謂連編就是把函數(shù)名與函數(shù)體的程序代碼連接在一起的過(guò)程。靜態(tài)連編就是在編譯階段完成的連編。編譯時(shí)的多態(tài)是通過(guò)靜態(tài)連編來(lái)實(shí)現(xiàn)的。靜態(tài)連編時(shí),系統(tǒng)用實(shí)參與形參進(jìn)行匹配,對(duì)于同名的重載函數(shù)便根據(jù)參數(shù)上的差異進(jìn)行區(qū)分,然后進(jìn)行連編,從而實(shí)現(xiàn)了多態(tài)性。運(yùn)行時(shí)的多態(tài)是用動(dòng)態(tài)連編實(shí)現(xiàn)的。動(dòng)態(tài)連編時(shí)運(yùn)行階段完成的,即當(dāng)程序調(diào)用到某一函數(shù)名時(shí),才去尋找和連接其程序代碼,對(duì)面向?qū)ο蟪绦蛟O(shè)計(jì)而言,就是當(dāng)對(duì)象接收到某一消息時(shí),才去尋找和連接相應(yīng)的方法。

一般而言,編譯型語(yǔ)言(如C,Pascal)采用靜態(tài)連編,而解釋型語(yǔ)言(如LISP)采用動(dòng)態(tài)連編。靜態(tài)連編要求在程序編譯時(shí)就知道調(diào)用函數(shù)的全部信息。因此,這種連編類型的函數(shù)調(diào)用速度快、效率高,但缺乏靈活性;而動(dòng)態(tài)連編方式恰好相反,采用這種連編方式,一直要到程序運(yùn)行時(shí)才能確定調(diào)用哪個(gè)函數(shù),它降低了程序的運(yùn)行效率,但增強(qiáng)了程序的靈活性。純粹的面向?qū)ο蟪绦蛘Z(yǔ)言由于其執(zhí)行機(jī)制是消息傳遞,所以只能采用動(dòng)態(tài)連編。C++實(shí)際上采用了靜態(tài)連編和動(dòng)態(tài)連編相結(jié)合的方式。

在C++中,編譯時(shí)多態(tài)性主要是通過(guò)函數(shù)重載和運(yùn)算符重載實(shí)現(xiàn)的運(yùn)行時(shí)多態(tài)性主要是通過(guò)虛函數(shù)來(lái)實(shí)現(xiàn)的。

~

6.2 虛函數(shù)

虛函數(shù)的定義是在基類中進(jìn)行的,它是在基類中需要定義為虛函數(shù)的成員函數(shù)的聲明中冠以關(guān)鍵字virtual,從而提供一種接口界面。定義虛函數(shù)的方法如下:

virtual 返回類型 函數(shù)名(形參表) {
    函數(shù)體
}

在基類中的某個(gè)成員函數(shù)被聲明為虛函數(shù)后,此虛函數(shù)就可以在一個(gè)或多個(gè)派生類中被重新定義。虛函數(shù)在派生類中重新定義時(shí),其函數(shù)原型,包括返回類型、函數(shù)名、參數(shù)個(gè)數(shù)、參數(shù)類型的順序,都必須與基類中的原型完全相同。

#include <iostream>
#include <string>
using namespace std;

class Family{
private:
	string flower;
public:
	Family(string name = '鮮花'): flower(name) { }
	string getName() {
		return flower;
	}
	virtual void like() {
		cout << '家人喜歡不同的花: ' << endl;
	}
};

class Mother: public Family{
public:
	Mother(string name = '月季'): Family(name) { }
	void like() {
		cout << '媽媽喜歡' << getName() << endl;
	}
};

class Daughter: public Family{
public:
	Daughter(string name = '百合'): Family(name) { }
	void like() {
		cout << '女兒喜歡' << getName() << endl;
	}
};

int main() {
	Family *p;
	Family f;
	Mother mom;
	Daughter dau;
	p = &f;
	p->like();
	p = &mom;
	p->like();
	p = &dau;
	p->like();

	return 0;
}

程序運(yùn)行結(jié)果如下:

家人喜歡不同的花:
媽媽喜歡月季
女兒喜歡百合

C++規(guī)定,如果在派生類中,沒有用virtual顯式地給出虛函數(shù)聲明,這時(shí)系統(tǒng)就會(huì)遵循以下的規(guī)則來(lái)判斷一個(gè)成員函數(shù)是不是虛函數(shù):該函數(shù)與基類的虛函數(shù)是否有相同的名稱、參數(shù)個(gè)數(shù)以及對(duì)應(yīng)的參數(shù)類型、返回類型或者滿足賦值兼容的指針、引用型的返回類型。

下面對(duì)虛函數(shù)的定義做幾點(diǎn)說(shuō)明

  • 由于虛函數(shù)使用的基礎(chǔ)是賦值兼容規(guī)則,而賦值兼容規(guī)則成立的前提條件是派生類從其基類公有派生。因此,通過(guò)定義虛函數(shù)來(lái)使用多態(tài)性機(jī)制時(shí),派生類必須從它的基類公有派生。
  • 必須首先在基類中定義虛函數(shù);
  • 在派生類對(duì)基類中聲明的虛函數(shù)進(jìn)行重新定義時(shí),關(guān)鍵字virtual可以寫也可以不寫。
  • 雖然使用對(duì)象名和點(diǎn)運(yùn)算符的方式也可以調(diào)用虛函數(shù),如mom.like()可以調(diào)用虛函數(shù)Mother::like()。但是,這種調(diào)用是在編譯時(shí)進(jìn)行的靜態(tài)連編,它沒有充分利用虛函數(shù)的特性,只有通過(guò)基類指針訪問(wèn)虛函數(shù)時(shí)才能獲得運(yùn)行時(shí)的多態(tài)性
  • 一個(gè)虛函數(shù)無(wú)論被公有繼承多少次,它仍然保持其虛函數(shù)的特性。
  • 虛函數(shù)必須是其所在類的成員函數(shù),而不能是友元函數(shù),也不能是靜態(tài)成員函數(shù),因?yàn)樘摵瘮?shù)調(diào)用要靠特定的對(duì)象來(lái)決定該激活哪個(gè)函數(shù)。
  • 內(nèi)聯(lián)函數(shù)不能是虛函數(shù),因?yàn)閮?nèi)聯(lián)函數(shù)是不能在運(yùn)行中動(dòng)態(tài)確定其位置的。即使虛函數(shù)在類的內(nèi)部定義,編譯時(shí)仍將其看做非內(nèi)聯(lián)的。
  • 構(gòu)造函數(shù)不能是虛函數(shù),但是析構(gòu)函數(shù)可以是虛函數(shù),而且通常說(shuō)明為虛函數(shù)。

~

在一個(gè)派生類中重新定義基類的虛函數(shù)是函數(shù)重載的另一種形式。

多繼承可以視為多個(gè)單繼承的組合,因此,多繼承情況下的虛函數(shù)調(diào)用與單繼承下的虛函數(shù)調(diào)用由相似之處。

~

6.3 虛析構(gòu)函數(shù)

如果在主函數(shù)中用new運(yùn)算符建立一個(gè)派生類的無(wú)名對(duì)象和定義一個(gè)基類的對(duì)象指針,并將無(wú)名對(duì)象的地址賦值給這個(gè)對(duì)象指針,當(dāng)用delete運(yùn)算符撤銷無(wú)名對(duì)象時(shí),系統(tǒng)只執(zhí)行基類的析構(gòu)函數(shù),而不執(zhí)行派生類的析構(gòu)函數(shù)。

Base *p;
p = new Derived;
delete p;
-----------------
輸出:調(diào)用基類Base的析構(gòu)函數(shù)

原因是當(dāng)撤銷指針p所指的派生類的無(wú)名對(duì)象,而調(diào)用析構(gòu)函數(shù)時(shí),采用了靜態(tài)連編方式,只調(diào)用了基類Base的析構(gòu)函數(shù)。

如果希望程序執(zhí)行動(dòng)態(tài)連編方式,在用delete運(yùn)算符撤銷派生類的無(wú)名對(duì)象時(shí),先調(diào)用派生類的析構(gòu)函數(shù),再調(diào)用基類的析構(gòu)函數(shù),可以將基類的析構(gòu)函數(shù)聲明為虛析構(gòu)函數(shù)。一般格式為

virtual ~類名(){
    ·····
}

雖然派生類的析構(gòu)函數(shù)與基類的析構(gòu)函數(shù)名字不相同,但是如果將基類的析構(gòu)函數(shù)定義為虛函數(shù),由該類所派生的所有派生類的析構(gòu)函數(shù)也都自動(dòng)成為虛函數(shù)。示例如下,

#include <iostream>
#include <string>
using namespace std;

class Base{
public:
	virtual ~Base() {
		cout << '調(diào)用基類Base的析構(gòu)函數(shù)...' << endl;
	}
};

class Derived: public Base{
public:
	~Derived() {
		cout << '調(diào)用派生類Derived的析構(gòu)函數(shù)...' << endl;
	}
};

int main() {
	Base *p;
	p = new Derived;
	delete p;
	return 0;
}

輸出如下:

調(diào)用派生類Derived的析構(gòu)函數(shù)...
調(diào)用基類Base的析構(gòu)函數(shù)...

~

6.4 純虛函數(shù)

純虛函數(shù)是在聲明虛函數(shù)時(shí)被“初始化為0的函數(shù)”,聲明純虛函數(shù)的一般形式如下:

virtual 函數(shù)類型 函數(shù)名(參數(shù)表) = 0;

聲明為純虛函數(shù)后,基類中就不再給出程序的實(shí)現(xiàn)部分。純虛函數(shù)的作用是在基類中為其派生類保留一個(gè)函數(shù)的名字,以便派生類根據(jù)需要重新定義。

~

6.5 抽象類

如果一個(gè)類至少有一個(gè)純虛函數(shù),那么就稱該類為抽象類,對(duì)于抽象類的使用有以下幾點(diǎn)規(guī)定:

  • 由于抽象類中至少包含一個(gè)沒有定義功能的純虛函數(shù)。因此,抽象類只能作為其他類的基類來(lái)使用,不能建立抽象類對(duì)象。
  • 不允許從具體類派生出抽象類。所謂具體類,就是不包含純虛函數(shù)的普通類。
  • 抽象類不能用作函數(shù)的參數(shù)類型、函數(shù)的返回類型或是顯式轉(zhuǎn)換的類型。
  • 可以聲明指向抽象類的指針或引用,此指針可以指向它的派生類,進(jìn)而實(shí)現(xiàn)多態(tài)性。
  • 如果派生類中沒有定義純虛函數(shù)的實(shí)現(xiàn),而派生類中只是繼承基類的純虛函數(shù),則這個(gè)派生類仍然是一個(gè)抽象類。如果派生類中給出了基類純虛函數(shù)的實(shí)現(xiàn),則該派生類就不再是抽象類了,它是一個(gè)可以建立對(duì)象的具體類了。

~

6.6 示例:利用多態(tài)計(jì)算面積

應(yīng)用C++的多態(tài)性,計(jì)算三角形、矩形和圓的面積。

#include <iostream>
using namespace std;

/*** 定義一個(gè)公共基類 ***/
class Figure{
protected:
	double x, y;
public:
	Figure(double a, double b): x(a), y(b) {  }
	virtual void getArea()      //虛函數(shù)
	{  
		cout << 'No area computation defind for this class.\n';
	}
};

class Triangle: public Figure{
public:
	Triangle(double a, double b): Figure(a, b){  }
	//虛函數(shù)重定義,用于求三角形的面積
	void getArea(){
		cout << 'Triangle with height ' << x << ' and base ' << y;
		cout << ' has an area of ' << x * y * 0.5 << endl;
	}
};

class Square: public Figure{
public:
	Square(double a, double b): Figure(a, b){  }
	//虛函數(shù)重定義,用于求矩形的面積
	void getArea(){
		cout << 'Square with dimension ' << x << ' and ' << y;
		cout << ' has an area of ' << x * y << endl;
	}
};

class Circle: public Figure{
public:
	Circle(double a): Figure(a, a){  }
	//虛函數(shù)重定義,用于求圓的面積
	void getArea(){
		cout << 'Circle with radius ' << x ;
		cout << ' has an area of ' << x * x * 3.14 << endl;
	}
};

int main(){
	Figure *p;
	Triangle t(10.0, 6.0);
	Square s(10.0, 6.0);
	Circle c(10.0);

	p = &t;
	p->getArea();
	p = &s;
	p->getArea();
	p = &c;
	p->getArea();

	return 0;
}

程序輸出如下:

Triangle with height 10 and base 6 has an area of 30
Square with dimension 10 and 6 has an area of 60
Circle with radius 10 has an area of 314

七、運(yùn)算符重載

運(yùn)算符重載是面向?qū)ο蟪绦蛟O(shè)計(jì)的重要特征。

~

7.1 運(yùn)算符重載概述

運(yùn)算符重載是對(duì)已有的運(yùn)算符賦予多重含義,使同一個(gè)運(yùn)算符作用于不同類型的數(shù)據(jù)導(dǎo)致不同的行為。

下面的案例實(shí)現(xiàn)+號(hào)運(yùn)算符重載:

#include <iostream>
using namespace std;

class Complex{
private:
	double real, imag;
public:
	Complex(double r = 0.0, double i = 0.0): real(r), imag(i) { }
	friend Complex operator+(Complex& a, Complex& b) {
		Complex temp;
		temp.real = a.real + b.real;
		temp.imag = a.imag + b.imag;
		return temp;
	}
	void display() {
		cout << real;
		if (imag > 0) cout << '+';
		if (imag != 0) cout << imag << 'i' << endl;
	}
};

int main()
{
	Complex a(2.3, 4.6), b(3.6, 2.8), c;
	a.display();
	b.display();
	c = a + b;
	c.display();
	c = operator+(a, b);
	c.display();

	return 0;
}

程序輸出結(jié)果如下:

2.3+4.6i
3.6+2.8i
5.9+7.4i
5.9+7.4i

~

這一章偷個(gè)懶??


八、函數(shù)模板與類模板

利用模板機(jī)制可以顯著減少冗余信息,能大幅度地節(jié)約程序代碼,進(jìn)一步提高面向?qū)ο蟪绦虻目芍赜眯院涂删S護(hù)性。模板是實(shí)現(xiàn)代碼重用機(jī)制的一種工具,它可以實(shí)現(xiàn)類型參數(shù)化,即把類型定義為參數(shù),從而實(shí)現(xiàn)代碼的重用,使得一段程序可以用于處理多種不同類型的對(duì)象,大幅度地提高程序設(shè)計(jì)的效率。

~

8.1 模板的概念

在程序設(shè)計(jì)中往往存在這樣的現(xiàn)象:兩個(gè)或多個(gè)函數(shù)的函數(shù)體完全相同,差別僅在與它們的參數(shù)類型不同。

例如:

int Max(int x, int y) {
    return x >= y ? x : y;
}

double Max(double x, double y) {
    return x >= y ? x : y;
}

能否為上述這些函數(shù)只寫出一套代碼呢?解決這個(gè)問(wèn)題的一種方式是使用宏定義

#define Max(x, y)((x >= y) ? x : y)

宏定義帶來(lái)的另一個(gè)問(wèn)題是,可能在不該替換的地方進(jìn)行了替換,而造成錯(cuò)誤。事實(shí)上,由于宏定義會(huì)造成不少麻煩,所以在C++中不主張使用宏定義。解決以上問(wèn)題的另一個(gè)方法就是使用模板。

~

8.2 函數(shù)模板

所謂函數(shù)模板,實(shí)際上是建立一個(gè)通用函數(shù),其函數(shù)返回類型和形參類型不具體指定,用一個(gè)虛擬的類型來(lái)代表,這個(gè)通用函數(shù)就稱為函數(shù)模板。在調(diào)用函數(shù)時(shí),系統(tǒng)會(huì)根據(jù)實(shí)參的類型(模板實(shí)參)來(lái)取代模板中的虛擬類型,從而實(shí)現(xiàn)不同函數(shù)的功能。

函數(shù)的聲明格式如下

template <typename 類型參數(shù)>
返回類型 函數(shù)名(模板形參表)
{
    函數(shù)體
}
也可以定義為如下形式
template <class 類型參數(shù)>
返回類型 函數(shù)名(模板形參表)
{
    函數(shù)體
}

實(shí)際上,template是一個(gè)聲明模板的關(guān)鍵字,它表示聲明一個(gè)模板。類型參數(shù)(通常用C++標(biāo)識(shí)符表示,如T、type等)實(shí)際上是一個(gè)虛擬的類型名,使用前并未指定它是哪一種具體的類型,但使用函數(shù)模板時(shí),必須將類型實(shí)例化。類型參數(shù)前需加關(guān)鍵字typenameclass,typenameclass的作用相同,都是表示一個(gè)虛擬的類型名(即類型參數(shù))。

例1:一個(gè)與指針有關(guān)的函數(shù)模板

#include <iostream>
using namespace std;

template <typename T>
T Max(T *array, int size = 0) {
	T max = array[0];
	for (int i = 1	; i < size; i++) {
		if (array[i] > max) max = array[i];
	}
	return max;
}

int main() {
	int array_int[] = {783, 78, 234, 34, 90, 1};
	double array_double[] = {99.02, 21.9, 23.90, 12.89, 1.09, 34.9};
	int imax = Max(array_int, 6);
	double dmax = Max(array_double, 6);
	cout << '整型數(shù)組的最大值是:' << imax << endl;
	cout << '雙精度型數(shù)組的最大值是:' << dmax << endl;
	return 0;
}

例2:函數(shù)模板的重載

#include <iostream>
using namespace std;

template <class Type>
Type Max(Type x, Type y) {
	return x > y ? x : y;
}

template <class Type>
Type Max(Type x, Type y, Type z) {
	Type t = x > y ? x : y;
	t = t > z ? t : z;
	return t;
}

int main() {
	cout << '33,66中最大值為 ' << Max(33, 66) << endl;
	cout << '33,66,44中最大值為 ' << Max(33, 66, 44) << endl;
	return 0;
}

注意:

  • 在函數(shù)模板中允許使用多個(gè)類型參數(shù)。但是,應(yīng)當(dāng)注意template定義部分的每個(gè)類型參數(shù)前必須有關(guān)鍵字typename或class。
  • 在template語(yǔ)句與函數(shù)模板定義語(yǔ)句之間不允許插入別的語(yǔ)句。
  • 同一般函數(shù)一樣,函數(shù)模板也可以重載。
  • 函數(shù)模板與同名的非模板函數(shù)可以重載。在這種情況下,調(diào)用的順序是:首先尋找一個(gè)參數(shù)完全匹配的非模板函數(shù),如果找到了就調(diào)用它;若沒有找到,則尋找函數(shù)模板,將其實(shí)例化,產(chǎn)生一個(gè)匹配的模板參數(shù),若找到了,就調(diào)用它。

~

8.3 類模板

所謂類模板,實(shí)際上就是建立一個(gè)通用類,其數(shù)據(jù)成員、成員函數(shù)的返回類型和形參類型不具體指定,用一個(gè)虛擬的類型來(lái)代表。使用類模板定義對(duì)象時(shí),系統(tǒng)會(huì)根據(jù)實(shí)參的類型來(lái)取代類模板中虛擬類型,從而實(shí)現(xiàn)不同類的功能。

template <typename T>
class Three{
private:
    T x, y, z;
public:
    Three(T a, T b, T c) {
        x = a; y = b; z = c;
    }
    T sum() {
        return x + y + z;
    }
}

上面的例子中,成員函數(shù)(其中含有類型參數(shù))是定義在類體內(nèi)的。但是,類模板中的成員函數(shù)也可以在類模板體外定義。此時(shí),若成員函數(shù)中有類型參數(shù)存在,則C++有一些特殊的規(guī)定:

  1. 需要在成員函數(shù)定義之前進(jìn)行模板聲明;
  2. 在成員函數(shù)名前要加上“類名<類型參數(shù)>::”;

在類模板體外定義的成員函數(shù)的一般形式如下:

template <typename 類型參數(shù)>
函數(shù)類型 類名<類型參數(shù)>::成員函數(shù)名(形參表)
{
    ·····
}

例如,上例中成員函數(shù)sum()在類外定義時(shí),應(yīng)該寫成

template<typename T>
T Three<T>::sum() {
    return x + y + z;
}

**例子:**棧類模板的使用

#include <iostream>
#include <string>
using namespace std;

const int size = 10;
template <class T>
class Stack{
private:
	T stack[size];
	int top;
public:
	void init() {
		top = 0;
	}
	void push(T t);
	T pop();
};

template <class T>
void Stack<T>::push(T t) {
	if (top == size) {
		cout << 'Stack is full!' << endl;
		return;
	}
	stack[top++] = t;
}

template <class T>
T Stack<T>::pop() {
	if (top == 0) {
		cout << 'Stack is empty!' <<endl;
		return 0;
	}
	return stack[--top];
}

int main() {
	Stack<string> st;
	st.init();
	st.push('aaa');
	st.push('bbb');
	cout << st.pop() << endl;
	cout << st.pop() << endl;

	return 0;
}

九、C++的輸入和輸出

~

9.1 C++為何建立自己的輸入/輸出系統(tǒng)

C++除了完全支持C語(yǔ)言的輸入輸出系統(tǒng)外,還定義了一套面向?qū)ο蟮妮斎?輸出系統(tǒng)。C++的輸入輸出系統(tǒng)比C語(yǔ)言更安全、可靠。

c++的輸入/輸出系統(tǒng)明顯地優(yōu)于C語(yǔ)言的輸入/輸出系統(tǒng)。首先,它是類型安全的、可以防止格式控制符與輸入輸出數(shù)據(jù)的類型不一致的錯(cuò)誤。另外,C++可以通過(guò)重載運(yùn)算符“>>”和'<<',使之能用于用戶自定義類型的輸入和輸出,并且向預(yù)定義類型一樣有效方便。C++的輸入/輸出的書寫形式也很簡(jiǎn)單、清晰,這使程序代碼具有更好的可讀性。

~

9.2 C++的流庫(kù)及其基本結(jié)構(gòu)

“流”指的是數(shù)據(jù)從一個(gè)源流到一個(gè)目的的抽象,它負(fù)責(zé)在數(shù)據(jù)的生產(chǎn)者(源)和數(shù)據(jù)的消費(fèi)者(目的)之間建立聯(lián)系,并管理數(shù)據(jù)的流動(dòng)。凡是數(shù)據(jù)從一個(gè)地方傳輸?shù)搅硪粋€(gè)地方的操作都是流的操作,從流中提取數(shù)據(jù)稱為輸入操作(通常又稱提取操作),向流中添加數(shù)據(jù)稱為輸出操作(通常又稱插入操作)。

C++的輸入/輸出是以字節(jié)流的形式實(shí)現(xiàn)的。在輸入操作中,字節(jié)流從輸入設(shè)備(如鍵盤、磁盤、網(wǎng)絡(luò)連接等)流向內(nèi)存;在輸出操作中,字節(jié)流從內(nèi)存流向輸出設(shè)備(如顯示器、打印機(jī)、網(wǎng)絡(luò)連接等)。字節(jié)流可以是ASCII碼、二進(jìn)制形式的數(shù)據(jù)、圖形/圖像、音頻/視頻等信息。文件和字符串也可以看成有序的字節(jié)流,分別稱為文件流和字符串流。

~

用于輸入/輸出的頭文件

C++編譯系統(tǒng)提供了用于輸入/輸出的I/O類流庫(kù)。I/O流類庫(kù)提供了數(shù)百種輸入/輸出功能,I/O流類庫(kù)中各種類的聲明被放在相應(yīng)的頭文件中,用戶在程序中用#include命令包含了有關(guān)的頭文件就相當(dāng)于在本程序中聲明了所需要用到的類。常用的頭文件有:

  • iostream包含了對(duì)輸入/輸出流進(jìn)行操作所需的基本信息。使用cincout等流對(duì)象進(jìn)行針對(duì)標(biāo)準(zhǔn)設(shè)備的I/O操作時(shí),須包含此頭文件。
  • fstream用于用戶管理文件的I/O操作。使用文件流對(duì)象進(jìn)行針對(duì)磁盤文件的操作,須包含此頭文件。
  • strstream用于字符串流的I/O操作。使用字符串流對(duì)象進(jìn)行針對(duì)內(nèi)存字符串空間的I/O操作,須包含此頭文件。
  • iomanip用于輸入/輸出的格式控制。在使用setw、fixed等大多數(shù)操作符進(jìn)行格式控制時(shí),須包含此頭文件。
用于輸入/輸出的流類

I/O流類庫(kù)中包含了許多用于輸入/輸出操作的類。其中,類istream支持流輸入操作,類ostream支持流輸出操作,類iostream同時(shí)支持流輸入和輸出操作。

下表列出了iostream流類庫(kù)中常用的流類,以及指出了這些流類在哪個(gè)頭文件中聲明。

類名類名說(shuō)明頭文件
抽象流基類ios流基類iostream
輸入流類istream通用輸入流類和其他輸入流的基類iostream
輸入流類ifstream輸入文件流類fstream
輸入流類istrstream輸入字符串流類strstream
輸出流類ostream通用輸出流類和其他輸出流的基類iostream
輸出流類ofstream輸出文件流類fstream
輸出流類ostrstream輸出字符串流類strstream
輸入/輸出流類iostream通用輸入輸出流類和其他輸入/輸出流的基類iostream
輸入/輸出流類fstream輸入/輸出文件流類fstream
輸入/輸出流類strstream輸入/輸出字符串流類strstream

~

9.3 預(yù)定義的流對(duì)象

用流定義的對(duì)象稱為流對(duì)象。與輸入設(shè)備(如鍵盤)相關(guān)聯(lián)的流對(duì)象稱為輸入流對(duì)象;與輸出設(shè)備(如屏幕)相聯(lián)系的流對(duì)象稱為輸出流對(duì)象。

C++中包含幾個(gè)預(yù)定義的流對(duì)象,它們是標(biāo)準(zhǔn)輸入流對(duì)象cin、標(biāo)準(zhǔn)輸出流對(duì)象cout、非緩沖型的標(biāo)準(zhǔn)出錯(cuò)流對(duì)象cerr和緩沖型的標(biāo)準(zhǔn)出錯(cuò)流對(duì)象clog

~

9.4 輸入/輸出流的成員函數(shù)

使用istream和類ostream流對(duì)象的一些成員函數(shù),實(shí)現(xiàn)字符的輸出和輸入。

1、put()函數(shù)
    cout.put(單字符/字符形變量/ASCII碼);
2、get()函數(shù)
    get()函數(shù)在讀入數(shù)據(jù)時(shí)可包括空白符,而提取運(yùn)算符“>>”在默認(rèn)情況下拒絕接收空白字符。
    cin.get(字符型變量)
3、getline()函數(shù)
    cin.getline(字符數(shù)組, 字符個(gè)數(shù)n, 終止標(biāo)志字符)
    cin.getline(字符指針, 字符個(gè)數(shù)n, 終止標(biāo)志字符)
4ignore()函數(shù)
    cin.ignore(n, 終止字符)
    ignore()函數(shù)的功能是跳過(guò)輸入流中n個(gè)字符(默認(rèn)個(gè)數(shù)為1),或在遇到指定的終止字符(默認(rèn)終止字符是EOF)時(shí)提前結(jié)束。

~

9.5 預(yù)定義類型輸入/輸出的格式控制

在很多情況下,需要對(duì)預(yù)定義類型(如int、float、double型等)的數(shù)據(jù)的輸入/輸出格式進(jìn)行控制。在C++中,仍然可以使用C中的printf()scanf()函數(shù)進(jìn)行格式化。除此之外,C++還提供了兩種進(jìn)行格式控制的方法:一種是使用ios類中有關(guān)格式控制的流成員函數(shù)進(jìn)行格式控制;另一種是使用稱為操作符的特殊類型的函數(shù)進(jìn)行格式控制。

1、用流成員函數(shù)進(jìn)行輸入/輸出格式控制

  1. 設(shè)置狀態(tài)標(biāo)志的流成員函數(shù)setf()
  2. 清除狀態(tài)標(biāo)志的流成員函數(shù)unsetf()
  3. 設(shè)置域?qū)挼牧鞒蓡T函數(shù)width()
  4. 設(shè)置實(shí)數(shù)的精度流成員函數(shù)precision()
  5. 填充字符的流成員函數(shù)fill()

2、使用預(yù)定義的操作符進(jìn)行輸入/輸出格式控制

3、使用用戶自定義的操作符進(jìn)行輸入/輸出格式控制

若為輸出流定義操作符函數(shù),則定義形式如下:
ostream &操作符名(ostream &stream)
{
    自定義代碼
    return stream;
}

若為輸入流定義操作符函數(shù),則定義形式如下:
istream &操作符名(istream &stream)
{
    自定義代碼
    return stream;
}

例如,

#include <iostream>
#include <iomanip>
using namespace std;

ostream &output(ostream &stream)
{
	stream.setf(ios::left);
	stream << setw(10) << hex << setfill('-');
	return stream;
}

int main() {
	cout << 123 << endl;
	cout << output << 123 << endl;
	return 0;
}

輸出結(jié)果如下:

123
7b--------

~

9.6 文件的輸入/輸出

所謂文件,一般指存放在外部介質(zhì)上的數(shù)據(jù)的集合。

文件流是以外存文件為輸入/輸出對(duì)象的數(shù)據(jù)流。輸出文件流是從內(nèi)存流向外存文件的數(shù)據(jù),輸入文件流是從外存流向內(nèi)存的數(shù)據(jù)。

根據(jù)文件中數(shù)據(jù)的組織形式,文件可分為兩類:文本文件和二進(jìn)制文件。

在C++中進(jìn)行文件操作的一般步驟如下:

  1. 為要進(jìn)行操作的文件定義一個(gè)流對(duì)象。
  2. 建立(或打開)文件。如果文件不存在,則建立該文件。如果磁盤上已存在該文件,則打開它。
  3. 進(jìn)行讀寫操作。在建立(或打開)的文件基礎(chǔ)上執(zhí)行所要求的輸入/輸出操作。
  4. 關(guān)閉文件。當(dāng)完成輸入/輸出操作時(shí),應(yīng)把已打開的文件關(guān)閉。

~

9.7 文件的打開與關(guān)閉

為了執(zhí)行文件的輸入/輸出,C++提供了3個(gè)文件流類。

類名說(shuō)明功能
istream輸入文件流類用于文件的輸入
ofstream輸出文件流類用于文件的輸出
fstream輸入/輸出文件流類用于文件的輸入/輸出

這3個(gè)文件流類都定義在頭文件fstream中。

要執(zhí)行文件的輸入/輸出,須完成以下幾件工作:

  1. 在程序中包含頭文件fstream。
  2. 建立流對(duì)象
  3. 使用成員函數(shù)open()打開文件。
  4. 進(jìn)行讀寫操作。
  5. 使用close()函數(shù)將打開的文件關(guān)閉。

~

9.8 文本文件的讀/寫

**例子:**把字符串“I am a student.”寫入磁盤文件text.txt中。

#include <iostream>
#include <fstream>
using namespace std;

int main() {
	ofstream fout('../test.txt', ios::out);
	if (!fout) {
		cout << 'Cannot open output file.' << endl;
		exit(1);
	}
	fout << 'I am a student.';
	fout.close();

	return 0;
}

**例子:**把磁盤文件test1.dat中的內(nèi)容讀出并顯示在屏幕上。

#include <iostream>
#include <fstream>
using namespace std;

int main() {
	ifstream fin('../test.txt', ios::in);
	if (!fin) {
		cout << 'Cannot open output file.' << endl;
		exit(1);
	}
	char str[80];
	fin.getline(str , 80);
	cout << str <<endl;
	fin.close();

	return 0;
}

~

9.9 二進(jìn)制文件的讀寫

用get()函數(shù)和put()函數(shù)讀/寫二進(jìn)制文件

**例子:**將a~z的26個(gè)英文字母寫入文件,而后從該文件中讀出并顯示出來(lái)。

#include <iostream>
#include <fstream>
using namespace std;

int cput() {
	ofstream outf('test.txt', ios::binary);
	if (!outf) {
		cout << 'Cannot open output file.\n';
		exit(1);
	}
	char ch = 'a';
	for (int i = 0; i < 26; i++) {
		outf.put(ch);
		ch++;
	}
	outf.close();
	return 0;
}

int cget() {
	fstream inf('test.txt', ios::binary);
	if (!inf) {
		cout << 'Cannot open input file.\n';
		exit(1);
	}
	char ch;
	while (inf.get(ch)) {
		cout << ch;
	}
	inf.close();
	return 0;
}

int main() {
	cput();
	cget();   //此處文件打不開,不知為什么。。。

	return 0;
}
用read()函數(shù)和write()函數(shù)讀寫二進(jìn)制文件

有時(shí)需要讀寫一組數(shù)據(jù)(如一個(gè)結(jié)構(gòu)變量的值),為此C++提供了兩個(gè)函數(shù)read()和write(),用來(lái)讀寫一個(gè)數(shù)據(jù)塊,這兩個(gè)函數(shù)最常用的調(diào)用格式如下:

inf.read(char *buf, int len);
outf.write(const char *buf, int len);

**例子:**將兩門課程的課程名和成績(jī)以二進(jìn)制形式存放在磁盤文件中。

#include <iostream>
#include <fstream>
using namespace std;

struct list{
	char course[15];
	int score;
};

int main() {
	list ob[2] = {'Computer', 90, 'History', 99};
	ofstream out('test.txt', ios::binary);
	if (!out) {
		cout << 'Cannot open output file.\n';
		abort();   //退出程序,作用與exit相同。
	}
	for (int i = 0; i < 2; i++) {
		out.write((char*) &ob[i], sizeof(ob[i]));
	}
	out.close();

	return 0;
}

**例子:**將上述例子以二進(jìn)制形式存放在磁盤文件中的數(shù)據(jù)讀入內(nèi)存。

#include <iostream>
#include <fstream>
using namespace std;

struct list{
	char course[15];
	int score;
};

int main() {
	list ob[2];
	ifstream in('test.txt', ios::binary);
	if (!in) {
		cout << 'Cannot open input file.\n';
		abort();
	}
	for (int i = 0; i < 2; i++) {
		in.read((char *) &ob[i], sizeof(ob[i]));
		cout << ob[i].course << ' ' << ob[i].score << endl; 
	}
	in.close();

	return 0;
}
檢測(cè)文件結(jié)束

在文件結(jié)束的地方有一個(gè)標(biāo)志位,即為EOF。采用文件流方式讀取文件時(shí),使用成員函數(shù)eof()可以檢測(cè)到這個(gè)結(jié)束符。如果該函數(shù)的返回值非零,表示到達(dá)文件尾。返回值為零表示未達(dá)到文件尾。該函數(shù)的原型是:

int eof();
函數(shù)eof()的用法示例如下:
ifstream ifs;
···
if (!ifs.eof())   //尚未到達(dá)文件尾
    ···
還有一個(gè)檢測(cè)方法就是檢查該流對(duì)象是否為零,為零表示文件結(jié)束。
ifstream ifs;
···
if (!ifs)
    ···
如下例子:
while (cin.get(ch))
    cut.put(ch);
這是一個(gè)很通用的方法,就是檢測(cè)文件流對(duì)象的某些成員函數(shù)的返回值是否為0,為0表示該流(亦即對(duì)應(yīng)的文件)到達(dá)了末尾。

從鍵盤上輸入字符時(shí),其結(jié)束符是Ctrl+Z,也就是說(shuō),按下【Ctrl+Z】組合鍵,eof()函數(shù)返回的值為真。

~


十、異常處理和命名空間

10.1 異常處理

程序中常見的錯(cuò)位分為兩大類:編譯時(shí)錯(cuò)誤運(yùn)行時(shí)錯(cuò)誤。編譯時(shí)的錯(cuò)誤主要是語(yǔ)法錯(cuò)誤,如關(guān)鍵字拼寫錯(cuò)誤、語(yǔ)句末尾缺分號(hào)、括號(hào)不匹配等。運(yùn)行時(shí)出現(xiàn)的錯(cuò)誤統(tǒng)稱為異常,對(duì)異常的處理稱為異常處理。

C++處理異常的辦法:如果在執(zhí)行一個(gè)函數(shù)的過(guò)程中出現(xiàn)異常,可以不在本函數(shù)中立即處理,而是發(fā)出一個(gè)信息,傳給它的上一級(jí)(即調(diào)用函數(shù))來(lái)解決,如果上一級(jí)函數(shù)也不能處理,就再傳給其上一級(jí),由其上一級(jí)處理。如此逐級(jí)上傳,如果到最高一級(jí)還無(wú)法處理,運(yùn)行系統(tǒng)一般會(huì)自動(dòng)調(diào)用系統(tǒng)函數(shù)terminate(),由它調(diào)用abort終止程序。

**例子:**輸入三角形的三條邊長(zhǎng),求三角形的面積。當(dāng)輸入邊的長(zhǎng)度小于0時(shí),或者當(dāng)三條邊都大于0時(shí)但不能構(gòu)成三角形時(shí),分別拋出異常,結(jié)束程序運(yùn)行。

#include <iostream>
#include <cmath>
using namespace std;

double triangle(double a, double b, double c) {
	double s = (a + b + c) / 2;
	if (a + b <= c || a + c <= b || b + c <= a) {
		throw 1.0;        //語(yǔ)句throw拋出double異常
	}
	return sqrt(s * (s - a) * (s - b) * (s - c));
}

int main() {
	double a, b, c;
	try {
		cout << '請(qǐng)輸入三角形的三個(gè)邊長(zhǎng)(a, b, c): ' << endl;
		cin >> a >> b >> c;
		if (a < 0 || b < 0 || c < 0) {
			throw 1;   //語(yǔ)句throw拋出int異常
		}
		while (a > 0 && b > 0 && c > 0) {
			cout << 'a = ' << a << ' b = ' << b << ' c = ' << c << endl;
			cout << '三角形的面積 = ' << triangle(a, b, c) << endl;
			cin >> a >> b >> c;
			if (a <= 0 || b <= 0 || c <= 0) {
				throw 1;
			}
		}
	} catch (double) {
		cout << '這三條邊不能構(gòu)成三角形...' << endl;
	} catch (int) {
		cout << '邊長(zhǎng)小于或等于0...' << endl;
	}
	return 0;
}

~

10.2 命名空間和頭文件命名規(guī)則

命名空間:一個(gè)由程序設(shè)計(jì)者命名的內(nèi)存區(qū)域。程序設(shè)計(jì)者可以根據(jù)需要指定一些有名字的命名空間,將各命名空間中聲明的標(biāo)識(shí)符與該命名空間標(biāo)識(shí)符建立關(guān)聯(lián),保證不同命名空間的同名標(biāo)識(shí)符不發(fā)生沖突。

1.帶擴(kuò)展名的頭文件的使用
在C語(yǔ)言程序中頭文件包括擴(kuò)展名.h,使用規(guī)則如下面例子
    #include <stdio.h>
2.不帶擴(kuò)展名的頭文件的使用
C++標(biāo)準(zhǔn)要求系統(tǒng)提供的頭文件不包括擴(kuò)展名.h,如string,string.h等。
    #include <cstring>

十一、STL標(biāo)準(zhǔn)模板庫(kù)

標(biāo)準(zhǔn)模板庫(kù)Standard Template Library)中包含了很多實(shí)用的組件,利用這些組件,程序員編程方便而高效。

11.1 Vector

vector容器與數(shù)組類似,包含一組地址連續(xù)的存儲(chǔ)單元。對(duì)vector容器可以進(jìn)行很多操作,包括查詢、插入、刪除等常見操作。

#include <iostream>
#include <vector>
using namespace std;

int main() {
	vector<int> nums;
	nums.insert(nums.begin(), 99);
	nums.insert(nums.begin(), 34);
	nums.insert(nums.end(), 1000);
	nums.push_back(669);

	cout << '\n當(dāng)前nums中元素為: ' << endl;
	for (int i = 0; i < nums.size(); i++)
		cout << nums[i] << ' ' ;

	cout << nums.at(2);
	nums.erase(nums.begin());
	nums.pop_back();

	cout << '\n當(dāng)前nums中元素為: ' << endl;
	for (int i = 0; i < nums.size(); i++)
		cout << nums[i] << ' ' ;

	return 0;
}

~

11.2 list容器

#include <iostream>
#include <list>
using namespace std;

int main() {
	list<int> number;
	list<int>::iterator niter;
	number.push_back(123);
	number.push_back(234);
	number.push_back(345);

	cout << '鏈表內(nèi)容:' << endl;
	for (niter = number.begin(); niter != number.end(); ++niter)
		cout << *niter << endl;
	number.reverse();
	cout << '逆轉(zhuǎn)后的鏈表內(nèi)容:' << endl;
	for (niter = number.begin(); niter != number.end(); ++niter)
		cout << *niter << endl;
	number.reverse();

	return 0;
}

~

11.3 stack

**例子:**利用棧進(jìn)行進(jìn)制轉(zhuǎn)換

#include <iostream>
#include <stack>
using namespace std;

int main() {
	stack<int> st;
	int num = 100;
	cout << '100的八進(jìn)制表示為:';
	while (num) {
		st.push(num % 8);
		num /= 8;
	}
	int t;
	while (!st.empty()) {
		t = st.top();
		cout << t;
		st.pop();
	}
	cout << endl;

	return 0;
}

~

11.4 queue

#include <iostream>
#include <queue>
using namespace std;

int main() {
	queue<int> qu;
	for (int i = 0; i < 10; i++) 
		qu.push(i * 3 + i);
	while (!qu.empty()) {
		cout << qu.front() << ' ';
		qu.pop();
	}
	cout << endl;

	return 0;
}

~

11.5 優(yōu)先隊(duì)列priority_queue

#include <iostream>
#include <queue>
#include <functional>
#include <cstdlib>
#include <ctime>
using namespace std;

int main() {
	priority_queue<int> pq;
	srand((unsigned)time(0));
	for (int i = 0; i < 6; i++) {
		int t = rand();
		cout << t << endl;
		pq.push(t);
	}
	cout << '優(yōu)先隊(duì)列的值:' << endl;
	for (int i = 0; i < 6; i++) {
		cout << pq.top() << endl;
		pq.pop();
	}

	return 0;
}

~

11.6 雙端隊(duì)列deque

push_back();
push_front();
insert();
pop_back();
pop_front();
erase();
begin();
end();
rbegin();
rend();
size();
maxsize();

~

11.7 set

#include <iostream>
#include <set>
#include <string>
using namespace std;

int main() {
	set<string> s;
	s.insert('aaa');
	s.insert('bbb');
	s.insert('ccc');
	if (s.count('aaa') != 0) {
		cout << '存在元素aaa' << endl;
	}
	set<string>::iterator iter;
	for (iter = s.begin(); iter != s.end(); ++iter) 
		cout << *iter << endl;

	return 0;
}

~

11.8 map

#include <iostream>
#include <map>
#include <string>
using namespace std;

int main() {
	map<string, int> m;
	m['aaa'] = 111;
	m['bbb'] = 222;
	m['ccc'] = 333;
	if (m.count('aaa')) {
		cout << '鍵aaa對(duì)應(yīng)的值為' << m.at('aaa') << endl;
		cout << '鍵aaa對(duì)應(yīng)的值為' << m['aaa'] << endl;
	}

	return 0;
}

完結(jié)撒花~~~??????????

博主就是在復(fù)習(xí)的過(guò)程中順便總結(jié)下知識(shí)點(diǎn),以便以后查看學(xué)習(xí)。

注:本博客僅供學(xué)習(xí)和參考,內(nèi)容較多,難免會(huì)有錯(cuò)誤,請(qǐng)大家多多包涵。如有侵權(quán)敬請(qǐng)告知。

參考資料《C++面向?qū)ο蟪绦蛟O(shè)計(jì)》陳維興、林小茶編著

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多