日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

7.1.2 定义改进的Sales_date类

發布時間:2024/4/18 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 7.1.2 定义改进的Sales_date类 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?? 改進后的類的數據成員將與之前定義的版本保持一致,它們包括:bookNO,string類型,表示ISBN編號;units_sold,unsigned類型,表示某本書的銷量;以及revenue,double類型,表示這本書的總銷售收入。

???????? 如前所述,我們的類將包含兩個成員函數:combine和isbn。此外,我們還將賦予Sales_date另一個成員函數用于返回售出書籍的平均價格,這個函數被命名為avg_price。因為avg_price的目的并非通用,所以它應該屬于類的實現的一部分,而非接口的一部分。

??????? 定義和聲明成員函數的方式與普通函數差不多。成員函數的聲明必須在類的內部,它的定義則可以在類的內部也可以在類的外部。作為接口組成部分的非成員函數,例如add、read和print等,它們的定義和聲明都在類的外部。

???????由此可知,改進的Sales_data類型應該如下所示:

struct Sales_data{// 新成員:關于Sales_data對象的操作std :: string isbn() const { return bookNo; }Sales_data & combine(const Sales_data&);double avg_price() const;// 數據成員相之前沒有變化sd :: string bookNo;unsigned units_sold = 0;double revenue = 0.0; }; // Sales_data的非成員接口函數 Sales_data add(const Sales_data&, const Sales_data&); std :: ostream &print(std :: ostream&, const Sales_data&); std :: istream &read(std :: istream, Sales_data&);

注:定義在類的內部的函數是隱式的inline函數。
定義成員函數

????????盡管所有成員都必須在內部聲明,但是成員函數體可以定義在類內也可以定義在類外。對于Sales_data類來說,isbn函數定義在了類內,而combine和avg_price定義在了類外。

???????我們首先介紹isbn函數,它的形參列表為空,返回值是一個string對象:

????????std :: string isbn( )?? const { return bookNo; }

和其他函數一樣,成員函數體也是一個語句快。在此例中只有一條return語句,用于返回Sales_data對象的bookNo數據成員。關于isbn函數一間很有意思的事情是:它是如何獲得bookNo成員所依賴的對象呢?

引入this

????????讓我們再一次觀察對isbn成員函數的調用:

????????total.isbn( )

在這里,我們使用了點運算符來訪問total對象的isbn成員,然后調用它。

????????在后面我們將介紹一種例外的形式,當我們調用成員函數時,實際上是在替某個對象調用它。如果isbn指向Sales_data的成員(例如bookNo),則它隱式地指向調用該函數的對象的成員。在上面所示的調用中,當isbn返回bookNo時,實際上它隱式地返回total.bookNo。

????????成員函數通過一個名為this的額外的隱式的參數來訪問調用它的那個對象。當我們調用一個成員函數時,用請求該函數的對象地址初始化this。例如,如果調用

??????? total.isbn( )

則編譯器負責把total的地址傳遞給isbn的隱式形參this,可以等價地認為編譯器將該調用重寫成了如下的形式:

??????? //?偽代碼,用于說明調用成員函數的實際執行過程

????????Sales_data :: isbn(&total)

其中,調用Sales_data的isbn成員時傳入了對象total的地址。

????????在成員函數內部,我們可以直接使用調用該函數的對象的成員,而無須通過成員訪問運算符做到這一點,因為this所指的正是這個對象。任何對類成員的直接訪問都被看作this的隱式引用,也就是說,當isbn使用bookNo時,它隱式地使用this指向的成員,就像我們書寫了this->bookNo一樣。

????????對于我們來說,this形參是隱式定義的。實際上,任何自定義名為this的參數或變量的行為都是非法的。我們可以在成員函數體內部使用this,因此盡管沒必要,但我們還是能夠把isbn定義成如下的形式:

??????? std :: string isbn( )? const? { return this ->bookNo; }

????????因為this的目的總是指向“這個”對象,所以this是一個常量指針,我們不允許改變this中保存的地址。

引入const成員函數

???????isbn函數的另一個關鍵之處是緊隨參數列表之后的const關鍵字,這里,const的作用是修改隱式this指針的類型。

????????默認情況下,this的類型是指向類類型非常量版本的常量指針。例如在Sales_data成員函數中,this的類型是Sales_data *const。盡管this是隱式的,但是它仍然需要遵循初始化規則,意味著(在默認情況下)我們不能把this綁定到一個常量對象上。這一情況也就使得我們不能在一個常量對象上調用普通的成員函數。

????????如果isbn是一個普通函數而且this是一個普通的指針參數,則我們應該把this聲明成const?Sales_data *?const。畢竟在isbn函數體內不會改變this所指的對象,所以把this設置為指向常量的指針有助于提高函數的靈活性。

????????然而,this是隱式的并且不會出現在參數列表中,所以在哪兒將this聲明成指向常量的指針就成為我們必須面對的問題。C++語言的做法是允許把關鍵字const放在成員函數的參數列表之后,此時,緊跟在參數列表后面的const表示this是一個指向常量的指針。像這樣使用const的成員函數被稱作常量成員函數

????????可以把isbn的函數體想象成如下的形式:

??????? //?偽代碼,說明隱式的this指針是如何使用的

??????? //?下面的代碼是非法的:因為我們不能顯示地定義自己的this指針

??????? //?謹記此處的this是一個指向常量的指針,因為isbn是一個常量成員

??????? std :: string Sales_data :: isbn(const Sales_data *const this)? { return this -> bookNo; }?

注:常量對象,以及常量對象的引用或指針都只能調用常量成員函數。

類的作用域和成員函數

????????回顧之前所學的知識,類本身就是一個作用域。類的成員函數的定義嵌套在類的作用域之內,因此,isbn中用到的名字bookNo其實就是定義在Sales_data內的數據成員。

????????值得注意的是,即使bookNo定義在isbn之后,isbn也還是能夠使用bookNo。就如后面將要學習的那樣,編譯器分兩步處理類:首先編譯成員的聲明,然后才輪到成員函數體(如果有的話)。因此,成員函數體可以隨意使用類中的其他成員而無須在意這些成員出現的次序。

在類的外部定義成員函數

????????像其他函數一樣,當我們在類的外部定義成員函數時,成員函數的定義必須與它的聲明匹配。也就是說,返回類型、參數列表和函數名都得與類內部的聲明保持一致。如果成員被聲明成常量成員函數,那么它的定義也必須在參數列表后明確指定const屬性。同時,類外部定義的成員的名字必須包含它所屬的類名:

?????????double Sales_data :: avg_price( )? const? {

?????????????? if (units_sold)

???????????????????? return revenue / units_sold;

?????????????? else

?????????????????????return 0;

????????? }

函數名Sales_data :: avg_price使用作用域運算符來說明如下事實:我們定義了一個名為avg_price的函數,并且該函數被聲明在類Sales_data的作用域內。一旦編譯器看到這個函數名,就能理解剩余的代碼是位于類的作用域內的。因此,當avg_price使用revenue和units_sold時,實際上它隱式地使用了Sales_data的成員。

定義一個返回this對象的函數

???????函數combine的設計初衷類似于復合賦值運算符+=,調用該函數的對象代表的是賦值運算符左側的運算對象,右側運算對象則是通過顯示的實參被傳入函數:

??????? Sales_data & Sales_data :: combine(const Sales_data &rhs)

??????? {

???????????????? units_sold += rhs.units_sold;? //?把rhs的成員加到this對象的成員上

???????????????? revenue += rhs.revenue;

???????????????? return *this;???????? //?返回調用該函數的對象

???????? }

當我們的交易處理程序調用如下的函數時,

??????? total.combine(trans);??? //?更新變量total當前的值

total的地址被綁定到隱式的this參數上,而rhs綁定到了trans上。因此,當combine執行下面的語句時,

????????units_sold += rhs.units_sold;???? //?把rhs的承壓un添加到this對象的成員中

效果等同于求total.units_sold和trans.units_sold的和,然后把結果保存到total.units_sold中。

????????該函數一個值得關注的部分是它的返回類型和返回語句。一般來說,當我們定義的函數類似于某個內置運算符時,應該令該函數的行為盡量模仿這個運算符。內置的賦值運算符把它的左側運算對象當成左值返回,因此為了與它保持一致,combine函數必須返回引用類型。因為此時的左側運算對象是一個Sales_data的對象,所以返回類型應該是Sales_data&。

????????如前所述,我們無須使用隱式的this指針訪問函數調用者的某個具體成員,而是需要把調用函數的對象當成一個整體來訪問:

????????return *this;???? //?返回調用該函數的對象

其中,return語句解引用this指針以獲得執行該函數的對象,換句話說,上面的這個調用返回total的引用。

總結

以上是生活随笔為你收集整理的7.1.2 定义改进的Sales_date类的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。