摘要:構造函數的任務是初始化類對象的數據成員,無論何時只要類的對象被創建,就會執行構造函數。構造函數名字和類名相同,沒有返回類型。構造函數放在類的部分要求編譯器合成默認的構造函數。練習在你的類中添加構造函數,然后編寫一段程序令其用到每個構造函數。
std::string isbn() const {return bookNo};
↓
偽代碼:說明隱式的this
指針是如何使用的
下面的代碼是非法的:因為我們不能顯示地定義自己的this
指針, 在Sales_data成員函數中,this的類型是Sales_data *const
因為isbn是一個常量成員,此處的this是一個指向常量的指針
std::string Sales_data::isbn(const Sales_data *const this){ return this->isbn;}
.
來訪問成員函數total.isbn()
當isbn返回bookNo時,實際上它隱式的返回total.bookNo。成員函數通過一個名為this
的額外的隱式參數來訪問調用它的那個對象。this
偽代碼:Sales_data::isbn(&total)
this
,盡管沒有必要,但是能把isbn
定義成:std::string isbn() const {return this->bookNo}
const
作用:修改隱式this
指針的類型。緊跟在參數列表后面的const
表示this
是一個指向常量的指針 —— 使用const
的成員函數被稱為 常量成員函數。 const
成員函數:this
是指向const類類型的const
指針(既不能改變this
所指向的值,也不能改變this
保存的地址)。const
成員函數:this
是指向類類型的const
指針(可以改變this
所指向的值,不能改變this
保存的地址)。和類相關的非成員函數,定義和聲明都應該在類的外部。
一般來說,如果非成員函數是類接口的組成部分,則這些函數的聲明應該與類在同一個頭文件中。
public
部分= default
要求編譯器合成默認的構造函數。(C++11)Sales_item(): units_sold(0), revenue(0.0) { }
、public
:定義在public
后面的成員在整個程序內可以被訪問;public
成員定義類的接口private
:定義在private
后面的成員可以被類的成員函數訪問,但不能被使用該類的代碼訪問;private
隱藏了類的實現細節。class
和struct
:都可以被用于定義一個類,唯一的區別在于默認訪問權限。 class
:在第一個訪問說明符之前的成員是private
的。struct
:在第一個訪問說明符之前的成員是public
的。類可以允許其他類或者函數訪問它的非公有成員,方法是令其他類或者函數成為它的友元。如果類想把一個函數作為他的友元,只需要增加一條以friend
關鍵字開始的函數聲明語句即可。
friend
開始, friend Sales_data add(const Sales_data&, const Sales_data&);
表示非成員函數add
可以訪問類的非公有成員。inline
inline
。mutable
關鍵字:mutable data access_ctr;
const
,即使他是const
對象的成員const
或者是引用的話,必須將其初始化。只能初始化,不能賦值(注意初始化和賦值的區別) Sales_data(): Sales_data(" ", 0, 0) { }
只有當一個類沒有定義 任何構造函數的時候,編譯器才會生成一個默認構造函數。
如果構造函數只接受一個實參,則它實際上定義了轉換為此類類型的隱式轉換機制。這種構造函數又叫轉換構造函數(converting constructor)。
能通過一個實參調用的構造函數定義了一條從構造函數的參數類型向類類型隱式轉換的規則。
只允許 一步類類型轉換
抑制構造函數定義的隱式轉換
explicit
加以阻止explicit
關鍵字只允許出現在類內的構造函數聲明處(只對一個實參的構造函數有效)explicit
構造函數只能用于直接初始化,不能將explicit
構造函數用于拷貝形式的初始化過程。Sales_data item1(null_book); //正確,直接初始化Sales_data item2 = null_book; //錯誤:不能將 explicit 構造函數用于拷貝形式的初始化過程
explicit
的構造函數用于隱式轉換過程,但是我們可以使用這樣的構造函數 顯式地強制進行轉換。聚合類使得用戶可以直接訪問其成員,并且具有特殊的初始化語法形式。
滿足以下所有條件:
public
的virtual
函數可以使用一個花括號括起來的成員初始化列表,并用它初始化聚合類的數據成員。初始值的順序必須與聲明的順序一致。
constexpr
函數的參數和返回值必須是字面值類型constexpr
構造函數。constexpr
構造函數。static
數據成員存在于類類型的每個對象中。static
數據成員獨立于該類的任意對象而存在。static
數據成員是與類關聯的對象,并不與該類的對象相關聯。static
::
直接訪問靜態成員 r = Account::rate()
r = ac1.rate()
使用指針訪問:r = ac2->rate()
static
關鍵字,該關鍵字只出現在類內部的聲明語句。static
。double Account::interestRate = initRate();
constexpr
。使用2.6.1節定義的Sales_data
類為1.6節的交易處理程序編寫一個新版本。
解:
#include #include using std::cin; using std::cout; using std::endl; using std::string;struct Sales_data{ string bookNo; unsigned units_sold = 0; double revenue = 0.0;};int main(){ Sales_data total; if (cin >> total.bookNo >> total.units_sold >> total.revenue) { Sales_data trans; while (cin >> trans.bookNo >> trans.units_sold >> trans.revenue) { if (total.bookNo == trans.bookNo) { total.units_sold += trans.units_sold; total.revenue += trans.revenue; } else { cout << total.bookNo << " " << total.units_sold << " " << total.revenue << endl; total = trans; } } cout << total.bookNo << " " << total.units_sold << " " << total.revenue << endl; } else { std::cerr << "No data?!" << std::endl; return -1; } return 0;}
曾在2.6.2節的練習中編寫了一個Sales_data
類,請向這個類添加combine
函數和isbn
成員。
解:
#include struct Sales_data { std::string isbn() const { return bookNo; }; Sales_data& combine(const Sales_data&); std::string bookNo; unsigned units_sold = 0; double revenue = 0.0;};Sales_data& Sales_data::combine(const Sales_data& rhs){ units_sold += rhs.units_sold; revenue += rhs.revenue; return *this;}
修改7.1.1節的交易處理程序,令其使用這些成員。
解:
#include using std::cin; using std::cout; using std::endl;int main(){ Sales_data total; if (cin >> total.bookNo >> total.units_sold >> total.revenue) { Sales_data trans; while (cin >> trans.bookNo >> trans.units_sold >> trans.revenue) { if (total.isbn() == trans.isbn()) total.combine(trans); else { cout << total.bookNo << " " << total.units_sold << " " << total.revenue << endl; total = trans; } } cout << total.bookNo << " " << total.units_sold << " " << total.revenue << endl; } else { std::cerr << "No data?!" << std::endl; return -1; } return 0;}
編寫一個名為Person
的類,使其表示人員的姓名和地址。使用string
對象存放這些元素,接下來的練習將不斷充實這個類的其他特征。
解:
#include class Person { std::string name; std::string address;};
在你的Person
類中提供一些操作使其能夠返回姓名和地址。 這些函數是否應該是const
的呢?解釋原因。
解:
#include class Person { std::string name; std::string address;public: auto get_name() const -> std::string const& { return name; } auto get_addr() const -> std::string const& { return address; }};
應該是const
的。因為常量的Person
對象也需要使用這些函數操作。
對于函數add
、read
和print
,定義你自己的版本。
解:
#include #include struct Sales_data { std::string const& isbn() const { return bookNo; }; Sales_data& combine(const Sales_data&); std::string bookNo; unsigned units_sold = 0; double revenue = 0.0;};// member functions.Sales_data& Sales_data::combine(const Sales_data& rhs){ units_sold += rhs.units_sold; revenue += rhs.revenue; return *this;}// nonmember functionsstd::istream &read(std::istream &is, Sales_data &item){ double price = 0; is >> item.bookNo >> item.units_sold >> price; item.revenue = price * item.units_sold; return is;}std::ostream &print(std::ostream &os, const Sales_data &item){ os << item.isbn() << " " << item.units_sold << " " << item.revenue; return os;}Sales_data add(const Sales_data &lhs, const Sales_data &rhs){ Sales_data sum = lhs; sum.combine(rhs); return sum;}
使用這些新函數重寫7.1.2節練習中的程序。
int main(){ Sales_data total; if (read(std::cin, total)) { Sales_data trans; while (read(std::cin, trans)) { if (total.isbn() == trans.isbn()) total.combine(trans); else { print(std::cout, total) << std::endl; total = trans; } } print(std::cout, total) << std::endl; } else { std::cerr << "No data?!" << std::endl; return -1; } return 0;}
為什么read
函數將其Sales_data
參數定義成普通的引用,而print
函數將其參數定義成常量引用?
解:
因為read
函數會改變對象的內容,而print
函數不會。
對于7.1.2節練習中代碼,添加讀取和打印Person
對象的操作。
#include #include struct Person { std::string const& getName() const { return name; } std::string const& getAddress() const { return address; } std::string name; std::string address;};std::istream &read(std::istream &is, Person &person){ return is >> person.name >> person.address;}std::ostream &print(std::ostream &os, const Person &person){ return os << person.name << " " << person.address;}
在下面這條if
語句中,條件部分的作用是什么?
if (read(read(cin, data1), data2)) //等價read(std::cin, data1);read(std::cin, data2);
解:
read
函數的返回值是istream
對象, if
語句中條件部分的作用是從輸入流中讀取數據給兩個data
對象。
在你的Sales_data
類中添加構造函數, 然后編寫一段程序令其用到每個構造函數。
解:
頭文件
#include #include struct Sales_data { Sales_data() = default; Sales_data(const std::string &s):bookNo(s) { } Sales_data(const std::string &s, unsigned n, double p):bookNo(s), units_sold(n), revenue(n*p){ } Sales_data(std::istream &is); std::string isbn() const { return bookNo; }; Sales_data& combine(const Sales_data&); std::string bookNo; unsigned units_sold = 0; double revenue = 0.0;};// nonmember functionsstd::istream &read(std::istream &is, Sales_data &item){ double price = 0; is >> item.bookNo >> item.units_sold >> price; item.revenue = price * item.units_sold; return is;}std::ostream &print(std::ostream &os, const Sales_data &item){ os << item.isbn() << " " << item.units_sold << " " << item.revenue; return os;}Sales_data add(const Sales_data &lhs, const Sales_data &rhs){ Sales_data sum = lhs; sum.combine(rhs); return sum;}// member functions.Sales_data::Sales_data(std::istream &is){ read(is, *this);}Sales_data& Sales_data::combine(const Sales_data& rhs){ units_sold += rhs.units_sold; revenue += rhs.revenue; return *this;}
主函數
int main(){ Sales_data item1; print(std::cout, item1) << std::endl; Sales_data item2("0-201-78345-X"); print(std::cout, item2) << std::endl; Sales_data item3("0-201-78345-X", 3, 20.00); print(std::cout, item3) << std::endl; Sales_data item4(std::cin); print(std::cout, item4) << std::endl; return 0;}
把只接受一個istream
作為參數的構造函數移到類的內部。
解:
#include #include struct Sales_data;std::istream &read(std::istream&, Sales_data&);struct Sales_data { Sales_data() = default; Sales_data(const std::string &s):bookNo(s) { } Sales_data(const std::string &s, unsigned n, double p):bookNo(s), units_sold(n), revenue(n*p){ } Sales_data(std::istream &is) { read(is, *this); } std::string isbn() const { return bookNo; }; Sales_data& combine(const Sales_data&); std::string bookNo; unsigned units_sold = 0; double revenue = 0.0;};// member functions.Sales_data& Sales_data::combine(const Sales_data& rhs){ units_sold += rhs.units_sold; revenue += rhs.revenue; return *this;}// nonmember functionsstd::istream &read(std::istream &is, Sales_data &item){ double price = 0; is >> item.bookNo >> item.units_sold >> price; item.revenue = price * item.units_sold; return is;}std::ostream &print(std::ostream &os, const Sales_data &item){ os << item.isbn() << " " << item.units_sold << " " << item.revenue; return os;}Sales_data add(const Sales_data &lhs, const Sales_data &rhs){ Sales_data sum = lhs; sum.combine(rhs); return sum;}
使用istream
構造函數重寫第229頁的程序。
int main(){ Sales_data total(std::cin); if (!total.isbn().empty()) { std::istream &is = std::cin; while (is) { Sales_data trans(is); if (!is) break; if (total.isbn() == trans.isbn()) total.combine(trans); else { print(std::cout, total) << std::endl; total = trans; } } print(std::cout, total) << std::endl; } else { std::cerr << "No data?!" << std::endl; return -1; } return 0;}
編寫一個構造函數,令其用我們提供的類內初始值顯式地初始化成員。
Sales_data() : units_sold(0) , revenue(0) { }
為你的Person
類添加正確的構造函數。
#include #include struct Person;std::istream &read(std::istream&, Person&);struct Person{ Person() = default; Person(const std::string& sname, const std::string& saddr) :name(sname), address(saddr) {} Person(std::istream &is) { read(is, *this); } std::string getName() const { return name; } std::string getAddress() const { return address; } std::string name; std::string address;};std::istream &read(std::istream &is, Person &person){ is >> person.name >> person.address; return is;}std::ostream &print(std::ostream &os, const Person &person){ os << person.name << " " << person.address; return os;}
在類的定義中對于訪問說明符出現的位置和次數有限定嗎? 如果有,是什么?什么樣的成員應該定義在public
說明符之后? 什么樣的成員應該定義在private
說明符之后?
解:
在類的定義中對于訪問說明符出現的位置和次數沒有限定。
每個訪問說明符指定了接下來的成員的訪問級別,其有效范圍直到出現下一個訪問說明符或者達到類的結尾處為止。
如果某個成員能夠在整個程序內都被訪問,那么它應該定義為public
; 如果某個成員只能在類內部訪問,那么它應該定義為private
。
使用class
和struct
時有區別嗎?如果有,是什么?
解:
class
和struct
的唯一區別是默認的訪問級別不同。
封裝是何含義?它有什么用處?
將類內部分成員設置為外部不可見,而提供部分接口給外面,這樣的行為叫做封裝。
用處:
在你的Person
類中,你將把哪些成員聲明成public
的? 哪些聲明成private
的? 解釋你這樣做的原因。
構造函數、getName()
、getAddress()
函數將設為public
。 name
和 address
將設為private
。 函數是暴露給外部的接口,因此要設為public
; 而數據則應該隱藏讓外部不可見。
修改你的Sales_data
類使其隱藏實現的細節。 你之前編寫的關于Sales_data
操作的程序應該繼續使用,借助類的新定義重新編譯該程序,確保其正常工作。
#include #include class Sales_data { friend std::istream &read(std::istream &is, Sales_data &item); friend std::ostream &print(std::ostream &os, const Sales_data &item); friend Sales_data add(const Sales_data &lhs, const Sales_data &rhs);public: Sales_data() = default; Sales_data(const std::string &s):bookNo(s) { } Sales_data(const std::string &s, unsigned n, double p):bookNo(s), units_sold(n), revenue(n*p){ } Sales_data(std::istream &is) { read(is, *this); } std::string isbn() const { return bookNo; }; Sales_data& combine(const Sales_data&);private: std::string bookNo; unsigned units_sold = 0; double revenue = 0.0;};// member functions.Sales_data& Sales_data::combine(const Sales_data& rhs){ units_sold += rhs.units_sold; revenue += rhs.revenue; return *this;}// friend functionsstd::istream &read(std::istream &is, Sales_data &item){ double price = 0; is >> item.bookNo >> item.units_sold >> price; item.revenue = price * item.units_sold; return is;}std::ostream &print(std::ostream &os, const Sales_data &item){ os << item.isbn() << " " << item.units_sold << " " << item.revenue; return os;}Sales_data add(const Sales_data &lhs, const Sales_data &rhs){ Sales_data sum = lhs; sum.combine(rhs); return sum;}
修改你的Person
類使其隱藏實現的細節。
#include #include class Person { friend std::istream &read(std::istream &is, Person &person); friend std::ostream &print(std::ostream &os, const Person &person);public: Person() = default; Person(const std::string sname, const std::string saddr):name(sname), address(saddr){ } Person(std::istream &is){ read(is, *this); } std::string getName() const { return name; } std::string getAddress() const { return address; }private: std::string name; std::string address;};std::istream &read(std::istream &is, Person &person){ is >> person.name >> person.address; return is;}std::ostream &print(std::ostream &os, const Person &person){ os << person.name << " " << person.address; return os;}
編寫你自己的Screen
類型。
#include class Screen { public: using pos = std::string::size_type; Screen() = default; Screen(pos ht, pos wd, char c):height(ht), width(wd), contents(ht*wd, c){ } char get() const { return contents[cursor]; } char get(pos r, pos c) const { return contents[r*width+c]; } private: pos cursor = 0; pos height = 0, width = 0; std::string contents;};
給你的Screen
類添加三個構造函數:一個默認構造函數;另一個構造函數接受寬和高的值,然后將contents
初始化成給定數量的空白;第三個構造函數接受寬和高的值以及一個字符,該字符作為初始化后屏幕的內容。
#include class Screen { public: using pos = std::string::size_type; Screen() = default; // 1 Screen(pos ht, pos wd):height(ht), width(wd), contents(ht*wd, " "){ } // 2 Screen(pos ht, pos wd, char c):height(ht), width(wd), contents(ht*wd, c){ } // 3 char get() const { return contents[cursor]; } char get(pos r, pos c) const { return contents[r*width+c]; } private: pos cursor = 0; pos height = 0, width = 0; std::string contents;};
給你自己的Screen
類添加move
、set
和display
函數,通過執行下面的代碼檢驗你的類是否正確。
Screen myScreen(5, 5, "X");myScreen.move(4, 0).set("#").display(cout);cout << "/n";myScreen.display(cout);cout << "/n";
解:
增加代碼:
#include #include class Screen {public: ... ... inline Screen& move(pos r, pos c); inline Screen& set(char c); inline Screen& set(pos r, pos c, char ch); const Screen& display(std::ostream &os) const { do_display(os); return *this; } Screen& display(std::ostream &os) { do_display(os); return *this; }private: void do_display(std::ostream &os) const { os << contents; } ... ...};inline Screen& Screen::move(pos r, pos c){ cursor = r*width + c; return *this;}inline Screen& Screen::set(char c){ contents[cursor] = c; return *this;}inline Screen& Screen::set(pos r, pos c, char ch){ contents[r*width+c] = ch; return *this;}
測試代碼:
int main(){ Screen myScreen(5, 5, "X"); myScreen.move(4, 0).set("#").display(std::cout); std::cout << "/n"; myScreen.display(std::cout); std::cout << "/n"; return 0;}
如果move
、set
和display
函數的返回類型不是Screen&
而是Screen
,則在上一個練習中將會發生什么?
解:
如果返回類型是Screen
,那么move
返回的是*this
的一個副本,因此set
函數只能改變臨時副本而不能改變myScreen
的值。
修改你的Screen
類,令move
、set
和display
函數返回Screen
并檢查程序的運行結果,在上一個練習中你的推測正確嗎?
解:
推測正確。
#with "&"XXXXXXXXXXXXXXXXXXXX#XXXXXXXXXXXXXXXXXXXXXXXX#XXXX ^# without "&"XXXXXXXXXXXXXXXXXXXX#XXXXXXXXXXXXXXXXXXXXXXXXXXXXX ^
定義一對類X
和Y
,其中X
包含一個指向Y
的指針,而Y
包含一個類型為X
的對象。
class Y;class X { Y* y = nullptr;};class Y { X x;};
定義你自己的Screen
和Window_mgr
,其中clear
是Window_mgr
的成員,是Screen
的友元。
#include #include #include class Screen;class Window_mgr {public: using ScreenIndex = std::vector::size_type; //按照編號將指定的Screen置為空白 void clear(ScreenIndex); private: std::vector screen;};class Screen { friend void Window_mgr::clear(ScreenIndex);public: using pos = std::string::size_type; //構造函數 Screen() = default; Screen(pos ht, pos wd):height(ht),width(wd),contents(ht*wd," "){ } Screen(pos ht, pos wd, char c): height(ht),width(wd),contents(ht*wd,c){ } inline Screen& move(pos r, pos c); inline Screen& set(char c); inline Screen& set(pos r, pos c, char ch); const Screen& display(std::ostream& os) const { do_display(os); return *this; } Screen& display(std::ostream& os) { do_display(os); return *this; }private: pos cursor = 0; pos height = 0, width = 0; std::string contents; void do_display(std::ostream& os) const { os << contents; }};inline void Window_mgr::clear(ScreenIndex i){ Screen& s = screen[i]; s.contents = std::string(s.height * s.width, " ");}inline Screen& Screen::move(pos r, pos c){ cursor = r * width + c; return *this;}inline Screen& Screen::set(char c){ contents[cursor] = c; return *this;}inline Screen& Screen::set(pos r, pos c, char ch){ contents[r * width + c] = ch; return *this;}
如果我們把第256頁Screen
類的pos
的typedef
放在類的最后一行會發生什么情況?
解:
在 dummy_fcn(pos height) 函數中會出現 未定義的標識符pos。
類型名的定義通常出現在類的開始處,這樣就能確保所有使用該類型的成員都出現在類名的定義之后。
有些情況下我們希望提供cin
作為接受istream&
參數的構造函數的默認實參,請聲明這樣的構造函數。
解:
Sales_data(std::istream &is = std::cin) { read(is, *this); }
使用委托構造函數重新編寫你的Sales_data
類,給每個構造函數體添加一條語句,令其一旦執行就打印一條信息。用各種可能的方式分別創建Sales_data
對象,認真研究每次輸出的信息直到你確實理解了委托構造函數的執行順序。
頭文件
#ifndef CP5_ex7_41_h#define CP5_ex7_41_h#include #include class Sales_data { friend std::istream &read(std::istream &is, Sales_data &item); friend std::ostream &print(std::ostream &os, const Sales_data &item); friend Sales_data add(const Sales_data &lhs, const Sales_data &rhs);public: Sales_data(const std::string &s, unsigned n, double p):bookNo(s), units_sold(n), revenue(n*p) { std::cout << "Sales_data(const std::string&, unsigned, double)" << std::endl; } Sales_data() : Sales_data("", 0, 0.0f) { std::cout << "Sales_data()" << std::endl; } Sales_data(const std::string &s) : Sales_data(s, 0, 0.0f) { std::cout << "Sales_data(const std::string&)" << std::endl; } Sales_data(std::istream &is); std::string isbn() const { return bookNo; } Sales_data& combine(const Sales_data&); private: inline double avg_price() const; private: std::string bookNo; unsigned units_sold = 0; double revenue = 0.0;};inlinedouble Sales_data::avg_price() const{ return units_sold ? revenue/units_sold : 0;}// declarations for nonmember parts of the Sales_data interface.std::istream &read(std::istream &is, Sales_data &item);std::ostream &print(std::ostream &os, const Sales_data &item);Sales_data add(const Sales_data &lhs, const Sales_data &rhs);#endif
源文件
#include "ex_7_41.h"http:// constructorSales_data::Sales_data(std::istream &is) : Sales_data(){ std::cout << "Sales_data(istream &is)" << std::endl; read(is, *this);}// member functions.Sales_data& Sales_data::combine(const Sales_data& rhs){ units_sold += rhs.units_sold; revenue += rhs.revenue; return *this;}// friend functionsstd::istream &read(std::istream &is, Sales_data &item){ double price = 0; is >> item.bookNo >> item.units_sold >> price; item.revenue = price * item.units_sold; return is;}std::ostream &print(std::ostream &os, const Sales_data &item){ os << item.isbn() << " " << item.units_sold << " " << item.revenue; return os;}Sales_data add(const Sales_data &lhs, const Sales_data &rhs){ Sales_data sum = lhs; sum.combine(rhs); return sum;}
主函數
#include "ex_7_41.h"using std::cout; using std::endl;int main(){ cout << "1. default way: " << endl; cout << "----------------" << endl; Sales_data s1; cout << "/n2. use std::string as parameter: " << endl; cout << "----------------" << endl; Sales_data s2("CPP-Primer-5th"); cout << "/n3. complete parameters: " << endl; cout << "----------------" << endl; Sales_data s3("CPP-Primer-5th", 3, 25.8); cout << "/n4. use istream as parameter: " << endl; cout << "----------------" << endl; Sales_data s4(std::cin); return 0;}
輸出
1. default way:----------------Sales_data(const string& s, unsigned n, double p)Sales_data()2. use std::string as parameter:----------------Sales_data(const string& s, unsigned n, double p)Sales_data(const string& s)3. complete parameters:----------------Sales_data(const string& s, unsigned n, double p)4. use istream as parameter:----------------Sales_data(const string& s, unsigned n, double p)Sales_data()Sales_data(istream& is)
總結:使用委托構造函數,調用順序是:
假定有一個名為NoDefault
的類,它有一個接受int
的構造函數,但是沒有默認構造函數。定義類C
,C
有一個 NoDefault
類型的成員,定義C
的默認構造函數。
class NoDefault {public: NoDefault(int i) { }};class C {public: C() : def(0) { } private: NoDefault def;};
說明接受一個string
參數的Sales_data
構造函數是否應該是explicit
的,并解釋這樣做的優缺點。
解:
是否需要從string
到Sales_data
的轉換依賴于我們對用戶使用該轉換的看法。在此例中,這種轉換可能是對的。null_book
中的string
可能表示了一個不存在的ISBN
編號。
優點:
可以抑制構造函數定義的隱式轉換
缺點:
為了轉換要顯式地使用構造函數
假定Sales_data
的構造函數不是explicit
的,則下述定義將執行什么樣的操作?
解:
string null_isbn("9-999-9999-9");Sales_data item1(null_isbn);Sales_data item2("9-999-99999-9");
這些定義和是不是explicit
的無關。
對于combine
函數的三種不同聲明,當我們調用i.combine(s)
時分別發生什么情況?其中i
是一個Sales_data
,而s
是一個string
對象。
解:
(a) Sales_data &combine(Sales_data); // ok(b) Sales_data &combine(Sales_data&); // error C2664: 無法將參數 1 從“std::string”轉換為“Sales_data &” 因為隱式轉換只有一次(c) Sales_data &combine(const Sales_data&) const; // 該成員函數是const 的,意味著不能改變對象。而 combine函數的本意就是要改變對象
確定在你的Person
類中是否有一些構造函數應該是explicit
的。
explicit Person(std::istream& is) { read(is, *this); }
vector
將其單參數的構造函數定義成explicit
的,而string
則不是,你覺得原因何在?
假如我們有一個這樣的函數:
int getSize(const std::vector&);
如果vector
沒有將單參數構造函數定義成explicit
的,我們就可以這樣調用:
getSize(34);
很明顯這樣調用會讓人困惑,函數實際上會初始化一個擁有34個元素的vecto
r的臨時量,然后返回34。但是這樣沒有任何意義。而string
則不同,string
的單參數構造函數的參數是const char *
,因此凡是在需要用到string
的地方都可以用const char *
來代替(字面值就是const char *
)。如:
void print(std::string);print("hello world");
使用2.6.1節的 Sales_data
類,解釋下面的初始化過程。如果存在問題,嘗試修改它。
Sales_data item = {"987-0590353403", 25, 15.99};
解:
Sales_data
類不是聚合類,應該修改成如下:
struct Sales_data { std::string bookNo; unsigned units_sold; double revenue;};
定義你自己的Debug
。
解:
class Debug {public: constexpr Debug(bool b = true) : hw(b), io(b), other(b) { } constexpr Debug(bool h, bool i, bool o) : hw(r), io(i), other(0) { } constexpr bool any() { return hw || io || other; } void set_hw(bool b) { hw = b; } void set_io(bool b) { io = b; } void set_other(bool b) { other = b; } private: bool hw; // runtime error bool io; // I/O error bool other; // the others};
Debug
中以 set_
開頭的成員應該被聲明成constexpr
嗎?如果不,為什么?
解:
不能。constexpr
函數必須包含一個返回語句
7.5.5節的Data
類是字面值常量類嗎?請解釋原因。
解:
不是。因為std::string
不是字面值類型。
編寫你自己的Account
類。
解:
class Account {public: void calculate() { amount += amount * interestRate; } static double rate() { return interestRate; } static void rate(double newRate) { interestRate = newRate; } private: std::string owner; double amount; static double interestRate; static constexpr double todayRate = 42.42; static double initRate() { return todayRate; }};double Account::interestRate = initRate();
下面的靜態數據成員的聲明和定義有錯誤嗎?請解釋原因。
//example.hclass Example {public: static double rate = 6.5; static const int vecSize = 20; static vector vec(vecSize);};//example.c#include "example.h"double Example::rate;vector Example::vec;
解:
rate
應該是一個常量表達式。而類內只能初始化整型類型的靜態常量,所以不能在類內初始化vec
。修改后如下:
// example.hclass Example {public: static constexpr double rate = 6.5; static const int vecSize = 20; static vector vec;};// example.C#include "example.h"constexpr double Example::rate;vector Example::vec(Example::vecSize);
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/119304.html
小編寫這篇文章,主要目的還是給大家講一下關于python代碼的相關事宜,比如怎么才能夠實現自動生產C++代碼,這里面還是比較的復雜的,下面小編就給大家貼出具體的代碼給大家來看下。 遇到的問題 工作中遇到這么一個事,需要寫比較多的C++的底層數據庫類,但這些類大同小異,無非是增刪改查,如果人工來寫代碼,既費力又容易出錯;而借用python的代碼自動生成,可以輕松搞定; (類比JAVA中的H...
摘要:貢獻者飛龍版本最近總是有人問我,把這些資料看完一遍要用多長時間,如果你一本書一本書看的話,的確要用很長時間。為了方便大家,我就把每本書的章節拆開,再按照知識點合并,手動整理了這個知識樹。 Special Sponsors showImg(https://segmentfault.com/img/remote/1460000018907426?w=1760&h=200); 貢獻者:飛龍版...
摘要:協程定義協程的底層架構是在中定義,并在實現的。為了簡化,我們會使用裝飾器預激協程。執行上述代碼結果如下出錯的原因是發送給協程的值不能加到變量上。示例使用和方法控制協程。 最近找到一本python好書《流暢的python》,是到現在為止看到的對python高級特性講述最詳細的一本。看了協程一章,做個讀書筆記,加深印象。 協程定義 協程的底層架構是在pep342 中定義,并在python2...
閱讀 1637·2021-09-26 09:55
閱讀 1371·2021-09-23 11:22
閱讀 2726·2021-09-06 15:02
閱讀 2640·2021-09-01 11:43
閱讀 3951·2021-08-27 13:10
閱讀 3676·2021-08-12 13:24
閱讀 2069·2019-08-30 12:56
閱讀 2991·2019-08-30 11:22