(內(nèi)置數(shù)據(jù)類型 對(duì)象的定義 表達(dá)式 語句函數(shù)的定義和使用)
1.標(biāo)準(zhǔn) C++頭文件沒有后綴。
2.C++標(biāo)準(zhǔn)庫還提供了一組擴(kuò)展的基本數(shù)據(jù)類型 其中包括字符串 string 、復(fù)數(shù) complex number、 向量 vector 和列表 list 。
3.c++程序基本結(jié)構(gòu)實(shí)例函數(shù):
#includeusing namespace std;
void read() {cout<< "read()\n"; }
void sort() {cout<< "sort()\n"; }
void compact() {cout<< "compact()\n"; }
void write() {cout<< "write()\n"; }
int main()
{ read();
sort();
compact();
write();
return 0;
}
#ifdef 指示符常被用來判斷一個(gè)預(yù)處理器常量是否已被定義 以便有條件地包含程序代
碼 例如
#ifdef DEBUG
cout<< “Beginning execution of main()\n”;
#endif
5.文件輸出
#include#include#includeint main()
{ ofstream outfile( "out_file" );
ifstream infile( "in_file" );
if ( ! infile ) { cerr<< "error: unable to open input file!\n";
return -1;
}
if ( ! outfile ) { cerr<< "error: unable to open output file!\n";
return -2;
}
string word;
while ( infile >>word )
outfile<< word<< ' ';
return 0;
}
ch2 C++瀏覽練習(xí) 2.1 為什么內(nèi)置數(shù)組類型不支持?jǐn)?shù)組之間的賦值? 支持這種操作需要什么信息?
Answer:數(shù)組名其實(shí)代表著一個(gè)指針常量,所以將一個(gè)數(shù)組名賦值給另一個(gè)數(shù)組,就像是把常量2賦值給常量3一樣,雖然語法正確,但在語意層面上會(huì)產(chǎn)生錯(cuò)誤。C++語言并未支持?jǐn)?shù)組的賦值操作,編譯器在編譯時(shí)必須知道數(shù)組的長度,才能產(chǎn)生執(zhí)行代碼來支持?jǐn)?shù)組對(duì)數(shù)組的操作。*
練習(xí) 2.2 你認(rèn)為作為一等公民的數(shù)組應(yīng)該支持什么操作?
取得數(shù)組長度; .互相拷貝; .做相等比較;//不理解這個(gè)問題one-class
動(dòng)態(tài)對(duì)象的分配與釋放 必須由程序員顯式地管理 相對(duì)來說比較容易出錯(cuò)
它通過 new 和 delete 兩個(gè)表達(dá)式來完成
練習(xí) 2.3 說出下面定義的四個(gè)對(duì)象之間的區(qū)別 (a) int ival = 1024; ( c) int *pi2 = new int(
1024 ); (b) int *pi = & ival; (d) int *pi3 = new int[ 1024 ];answer:靜態(tài),分配了一個(gè)沒有名字的 int 類型的對(duì)象 對(duì)象初始值為 1024,指針指向ival,指針指向數(shù)組
練習(xí) 2.4 下面的代碼段是做什么的? 有什么嚴(yán)重錯(cuò)誤? 注意 指針 pia 的下標(biāo)操作符的用法是正確的 在 3.9.2
節(jié)中我們會(huì)解釋其理由 int *pi = new int( 10 ); int *pia = new int[ 10 ]; while
( *pi< 10 ) { pia[ *pi ] = *pi; *pi = *pi + 1; } delete pi;
delete [] pia;answer:轉(zhuǎn)載:
https://blog.csdn.net/yqzsl/article/details/5581744
我來解釋一下每行的代碼語義: //動(dòng)態(tài)分配一個(gè)int大小的內(nèi)存空間,其內(nèi)容初始化為10將其地址存放到pi中 int *pi = new
int( 10 );/動(dòng)態(tài)分配一個(gè)能容納10個(gè)int的內(nèi)存空間,未作初始化操作。 int *pia = new int[ 10 ];
//當(dāng)*pi(也就是10)小于10的時(shí)候,執(zhí)行循環(huán)語句 while ( *pi< 10 ) { //pia[ 10 ]
賦值為10將其開始地址存放到pia中pia[ *pi ] = *pi;
//*pi的內(nèi)容累加1
*pi = *pi + 1; }//釋放pi指向的整數(shù)內(nèi)存 delete pi;
//釋放pia指向的整數(shù)數(shù)組內(nèi)存 delete [] pia;
問題: 1)循環(huán)語句條件判斷為False,所以循環(huán)體中的語句根本不執(zhí)行。(理解) 2)
pia[]的index沒有經(jīng)過邊界檢測,在上例中,pia[]從0~9一共10個(gè)int元素,但是*pi的值為10,明顯是數(shù)組越界訪問。()
3)pia[]中的內(nèi)容未作初始化處理,里面包含垃圾數(shù)據(jù)。
// 相等與不相等操作 #2b
bool operator==( const IntArray& ) const;
bool operator!=( const IntArray& ) const;
// 賦值操作符 #2a
IntArray& operator=( const IntArray& );
????不理解這里
兩種操作符
用于類對(duì)象的點(diǎn)操作符 .
用于類對(duì)象指針的箭頭操作符 ->
下面 給出兩個(gè) IntArray 對(duì)象
IntArray myArray0, myArray1;
賦值操作符可以這樣應(yīng)用
// 調(diào)用拷貝賦值成員函數(shù)
// myArraya.operator=( myArray1 )
myArray0 = myArray1;
等于操作符的調(diào)用如下所示
// 調(diào)用等于成員函數(shù)
// myArray0.operator==( myArray1 )
if ( myArray0 == myArray1 )
cout<< "!!our assignment operator works!\n";
class IntArray {public:
// ...
int size() const {return _size; }
private:
// 內(nèi)部數(shù)據(jù)
int _size;
int *ia;
};
由于我們把_size 放在類的私有區(qū)內(nèi) 因此我們有必要聲明一個(gè)公有成員函數(shù) 以便允
許用戶訪問它的值 由于 C++不允許成員函數(shù)與數(shù)據(jù)成員共享同一個(gè)名字 所以在這樣的情
況下 一般的習(xí)慣是在數(shù)據(jù)成員名字前面加一個(gè)下劃線 _ 因此 我們有了公有訪問函數(shù)
size()和私有數(shù)據(jù)成員_size 在本書以前的版本中 我們?cè)谠L問函數(shù)前加上 get 或 set 實(shí)踐證
明這樣做有些累贅
IntArray::
IntArray( const IntArray &rhs )
{ // 拷貝構(gòu)造函數(shù)
_size = rhs._size;
ia = new int[ _size ];
for (int ix = 0; ix< _size; ix++ )
iz[ ix ] = rhs.ia[ ix ];
}
提到的概念:
類體的外面定義類的成員函數(shù)
雙冒號(hào) :: 操作符被稱為域操作符 scope operator
拷貝構(gòu)造函數(shù) copy constructor
一種新的復(fù)合類型 :引用 reference
析構(gòu)成員函數(shù) destructor member function 標(biāo)識(shí)用: ~
練習(xí) 2.5
C++類的關(guān)鍵特征是接口與實(shí)現(xiàn)的分離 接口是一些 用戶可以應(yīng)用到類對(duì)象上的操作
的集合 它由三部分構(gòu)成 這些操作的名字 它們的返回值 以及它們的參數(shù)表 一般地 這
些就是該類用戶所需要知道的全部內(nèi)容 私有實(shí)現(xiàn)包括為支持公有接口所必需的算法和數(shù)據(jù)
理想情況下 即使類的接口增長了 它也不用變得與以前的版本不相兼容 另一方面 在類的
生命周期內(nèi)其實(shí)現(xiàn)可以自由演化 從下面選擇一個(gè)抽象 指類 并為該類編寫一個(gè)公共接口
(a) Matrix ? Person (e) Pointer
(b) Boolean (d) Date (f) Point
練習(xí) 2.6
構(gòu)造函數(shù)和析構(gòu)函數(shù)是程序員提供的函數(shù) 它們既不構(gòu)造也不銷毀類的對(duì)象 編譯器自
動(dòng)把它們作用到這些對(duì)象上 因此構(gòu)造函數(shù) constructor 和析構(gòu)函數(shù) destructor 這兩個(gè)詞
多少有些誤導(dǎo) 當(dāng)我們寫
int main() {
IntArray myArray( 1024 );
// …
return 0;
}
在構(gòu)造函數(shù)被應(yīng)用之前 用于維護(hù) myArray 中數(shù)據(jù)成員的內(nèi)存已經(jīng)被分配了 實(shí)際上
編譯器在內(nèi)部把程序轉(zhuǎn)換成如下的代碼 注意這不是合法的 C++代碼5
int main() {
IntArray myArray;
// 偽 C++代碼–應(yīng)用構(gòu)造函數(shù)
myArray.IntArray::IntArray( 1024 );
// …
// 偽 C++代碼–應(yīng)用析構(gòu)函數(shù)
myArray.IntArray::~IntArray();
return 0;
}
類的構(gòu)造函數(shù)主要用來初始化類對(duì)象的數(shù)據(jù)成員 析構(gòu)函數(shù)主要負(fù)責(zé)釋放類對(duì)象在生命
期內(nèi)申請(qǐng)到的所有資源 請(qǐng)定義在練習(xí) 2.5 中選擇的類所需要的構(gòu)造函數(shù)集 你的類需要析
構(gòu)函數(shù)嗎
練習(xí) 2.7
在練習(xí) 2.5 和練習(xí) 2.6 中 你差不多已經(jīng)定義了使用該類的完整公有接口 我們還需
要定義一個(gè)拷貝賦值操作符 但是現(xiàn)在我們忽略這個(gè)事實(shí)——C++為 從一個(gè)類對(duì)象向另一
個(gè)類對(duì)象賦值 提供了缺省支持 問題在于 缺省的行為常常是不夠的 這將在 14.6 節(jié)中討
論 寫一個(gè)程序來實(shí)踐在前面兩個(gè)練習(xí)中定義的公有接口 用起來容易還是麻煩 你希望
重寫這些定義嗎 你能在重寫的同時(shí)保持兼容性嗎
class IntArray {public:
// 構(gòu)造函數(shù)
explicit IntArray( int size = DefaultArraySize );
IntArray( int *array, int array_size );
IntArray( const IntArray &rhs );
// 虛擬析構(gòu)函數(shù)
virtual ~IntArray() {delete [] ia; }
// 等于和不等于操作
bool operator==( const IntArray& ) const;
bool operator!=( const IntArray& ) const;
IntArray& operator=( const IntArray& );
int size() const {return _size; }
// 去掉了索引檢查功能 . . .
virtual int& operator[](int index) {return ia[index]; }
virtual void sort();
virtual int min() const;
virtual int max() const;
virtual int find( int value ) const;
protected:
// 參見 13.5 節(jié)的說明
static const int DefaultArraySize = 12;
void init( int sz, int *array );
int _size;
int *ia;
};
類型相關(guān)的函數(shù)標(biāo)記為虛函數(shù),它的算法由特定的基類或派生類的行為或?qū)崿F(xiàn)來決定
#ifndef IntArrayRC_H
#define IntArrayRC_H
#include "IntArray.h"
class IntArrayRC : public IntArray {public:
IntArrayRC( int sz = DefaultArraySize );
IntArrayRC( int *array, int array_size );
IntArrayRC( const IntArrayRC &rhs );
virtual int& operator[]( int );
private:
void check_range( int );
};
#endif
派生類對(duì)象的初始化過程是這樣的 首先自動(dòng)調(diào)用每個(gè)基類的構(gòu)造函數(shù)來初始化相關(guān)的基類子對(duì)象 然后再執(zhí)行派生類的構(gòu)造函數(shù) 從設(shè)計(jì)的角度來看派生類的構(gòu)造函數(shù)應(yīng)該只初始化那些在派生類中被定義的數(shù)據(jù)成員 而不是某類中的數(shù)據(jù)成員。
這個(gè)小程序?qū)崿F(xiàn)了 IntArray 與 IntArrayRC 兩個(gè)類的層次結(jié)構(gòu)
#include#include#includeextern void swap(IntArray&,int,int);
int main()
{ int array[ 4 ] = {0, 1, 2, 3 };
IntArray ia1( array, 4 );
IntArrayRC ia2( array, 4 );
// 錯(cuò)誤 一位偏移 off-by-one 應(yīng)該是 size-1
// IntArray 對(duì)象捕捉不到這個(gè)錯(cuò)誤
cout<< "swap() with IntArray ia1\n";
swap( ia1, 1, ia1.size() );
// ok: IntArrayRC 對(duì)象可以捕捉到這樣的錯(cuò)誤
cout<< "swap() with IntArrayRC ia2\n";
swap( ia2, 1, ia2.size() );
return 0;
}
編譯并執(zhí)行這個(gè)程序 產(chǎn)生如下結(jié)果
swap() with IntArray ia1
swap() with IntArrayRC ia2
練習(xí) 2.8
一般來說 類型/子類型繼承關(guān)系反映了一種 is-a 是一種 的關(guān)系 具有范圍檢查
功能的 ArrayRC 是一種 Array 一本書 Book 是一種圖書外借資源 LibraryRentalMaterial
有聲書 AudioBook 是一種書 Book 等等 下面哪些反映出這種 is-a 關(guān)系
(a)成員函數(shù)是一種(isA_kindOf)函數(shù)
(b)成員函數(shù)是一種類
?構(gòu)造函數(shù)是一種成員函數(shù)
(d)飛機(jī)是一種交通工具
(e)摩托車是一種卡車
(f)圓形是一種幾何圖形
(g)正方形是一種矩形
(h)汽車是一種飛機(jī)
(i)借閱者是一種圖書館
練習(xí) 2.9
判斷以下操作哪些可能是類型相關(guān)的 因此可把它們定義為虛擬函數(shù) 哪些可以在所有
類之間共享 對(duì)單個(gè)基類或派生類來說哪些是惟一的
(a) rotate(); (b) print();
? size(); (d) dateBorrowed();
(e) rewind(); (f) borrower();
(g) is_late(); (h) is_on_loan();
練習(xí) 2.10
對(duì)于保護(hù) protected 訪問級(jí)別的使用已經(jīng)有了一些爭論 有人認(rèn)為 使用保護(hù)訪問級(jí)別允許派生類直接訪問基類的成員 這破壞了封裝的概念 因此 所有的基類實(shí)現(xiàn)細(xì)節(jié)都應(yīng)該是私有的 private 另外一些人認(rèn)為 如果派生類不能直接訪問基類的成員 那么派生類的實(shí)現(xiàn)將無法有足夠的效率供用戶使用如果沒有關(guān)鍵字 protected 類的設(shè)計(jì)者將被迫把基類成員設(shè)置為 public 你怎樣認(rèn)為
練習(xí) 2.11
第二個(gè)爭論是關(guān)于將成員函數(shù)顯式地聲明為 virtual 的必要性 一些人認(rèn)為 這意味著如
果類的設(shè)計(jì)者沒有意識(shí)到一個(gè)函數(shù)需要被聲明為 virtual 則派生類的設(shè)計(jì)者就沒有辦法改寫
這個(gè)關(guān)鍵函數(shù) 因此 他們建議把所有成員函數(shù)都設(shè)置為 virtual 的 另一方面 虛擬函數(shù)比
非虛擬函數(shù)的效率要低一些 6
因?yàn)樗鼈儾荒鼙粌?nèi)聯(lián) 內(nèi)聯(lián)發(fā)生在編譯時(shí)刻 而虛擬函數(shù)是
在運(yùn)行時(shí)刻被處理的 所以它們可能是運(yùn)行時(shí)刻效率低下的原因之一 尤其是小巧而又被
頻繁調(diào)用的 與類型無關(guān)的函數(shù) 比如 Array 數(shù)組 的 size 函數(shù) 你又怎樣認(rèn)為呢
練習(xí) 2.12
下面的每個(gè)抽象類型都隱式地包含一族抽象子類型 例如 圖書館藏資料
LibraryRentalMaterial 抽象隱式地包含書 Book 音像 Puppet 視盤 Video 等
選擇其中一個(gè) 找出該抽象的子類型層次 并為這個(gè)層次指定一個(gè)小的公有接口 且其中包
括構(gòu)造函數(shù) 如果存在的話 指出哪些函數(shù)是虛擬的 并且寫一小段偽代碼程序來練習(xí)使用
這個(gè)公有接口
(a) Points (b) Employees
( c) Shapes (d) TelephoneNumbers
(e) BankAccounts (f) CourseOfferings
下面的例子演示了怎樣使用 Array 類模板
#include#include "Array.h"
int main()
{ const int array_size = 4;
// elemType 變成了 int
Arrayia(array_size);
// elemType 變成了 double
Arrayda(array_size);
// elemType 變成了 char
Arrayca(array_size);
int ix;
for ( ix = 0; ix< array_size; ++ix ) { ia[ix] = ix;
da[ix] = ix * 1.75;
ca[ix] = ix + 'a';
}
for ( ix = 0; ix< array_size; ++ix )
cout<< "[ "<< ix<< " ] ia: "<< ia[ix]<< "\tca: "<< ca[ix]<< "\tda: "<< da[ix]<< endl;
return 0;
}
練習(xí) 2.13
給出下列類型聲明
template class Array;
enum Status { … };
typedef stringPstring;
如果存在的話 下面哪些對(duì)象的定義是錯(cuò)誤的
(a) Array< int& >pri( 1024 );
(b) Array< Array >aai( 1024 );
? Array< complex< double >>acd( 1024 );
(d) Array< Status >as( 1024 );
(e) Array< Pstring >aps( 1024 );
練習(xí) 2.14
重寫下面的類定義 使它成為一個(gè)類模板
class example1 {
public:
example1( double min, double max );
example1( const double *array, int size );double& operator[]( int index ); bool operator==( const example1& )
const; bool insert( const double*, int ); bool insert( double );
double min() const { return _min; }; double max() const { return
_max; }; void min( double ); void max( double ); int count( double value ) const; private: int size; double *parray;
double _min; double _max; };
練習(xí) 2.15 給出如下的類模板 template class Example2 { public:
explicit Example2( elemType val = 0 ) : _val( val ){} bool min(
elemType value ) { return _val< value; } void value( elemType
new_val ) { _val = new_val; } void print( ostream &os ) { os<<
_val; } private: elemType _val; }; template ostream& operator<< ( ostream &os, const Example2 &ex ) {
ex.print( os ); return os; } 如下這樣寫會(huì)發(fā)生什么事情 (a) Example2< Array* >
ex1; (b) ex1.min( &ex1 ); ? Example2< int >sa( 1024 ), sb; (d)
sa = sb; (e) Example2< string >exs( “Walden” ); (f) cout<< "exs: "
<< exs<< endl;
練習(xí) 2.16 在 Example2 的定義中 我們寫 explicit Example2( elemType val = 0 ) : _val( val ){} 其意圖是指定一個(gè)缺省值 以便用戶可以寫 Example2< Type >ex1( value ); Example2< Type >ex2; 但是 我們的實(shí)現(xiàn)把 Type 限制在一個(gè) 不能用 0 進(jìn)行初始化的類型 的子集中 例如 用 0 初始化一個(gè) string 類型 就是一個(gè)錯(cuò)誤 7 類似的情況是 如果 Type 不支持輸出操作 符 那么 print()調(diào)用就會(huì)失敗 因此 Example2 的輸出操作符也會(huì)失敗 如果 Type 不支 持小于操作符 那么 min()調(diào)用就會(huì)失敗 ,C++語言本身并沒有提供可以指示在實(shí)例化模板時(shí) Type 有哪些隱含限制的方法 在最壞 的情況下 當(dāng)程序編譯失敗時(shí)程序員才發(fā)現(xiàn)這些限制,你認(rèn)為 C++語言應(yīng)該支持限制 Type 的語法嗎 如果你認(rèn)為應(yīng)該的話 請(qǐng)說明語法 并用它重寫 Example2 的定義 如果認(rèn)為不 需要
請(qǐng)說明理由
練習(xí) 2.17
在上一個(gè)練習(xí)中 我們說如果 Type 不支持輸出操作符和小于操作符 那么對(duì) print()和
min()的調(diào)用就會(huì)出錯(cuò) 在標(biāo)準(zhǔn) C++中 錯(cuò)誤的產(chǎn)生不是發(fā)生在類模板被創(chuàng)建的時(shí)候 而是在
print()與 min()被調(diào)用的時(shí)候 你認(rèn)為這樣的語義正確嗎 是否應(yīng)該在模板定義中標(biāo)記這個(gè)錯(cuò)
誤 為什么
在 C++中 異常的拋出由 throw 表達(dá)式來執(zhí)行 例如 在下面的程序段中 一個(gè) string 類型的異常被拋出來以便響應(yīng)打開文件失敗異常.C++中, 異常的處理由 catch 子句來執(zhí)行,catch 子句與 try 塊相關(guān)聯(lián) 一個(gè) try 塊用一個(gè)或多個(gè) catch 子句將一條或多條語句組織起來 .
if ( ! infile ) { string errMsg( "unable to open file: " );
errMsg += fileName;
throw errMsg;
}
練習(xí) 2.18
下面的函數(shù)對(duì)可能的非法數(shù)據(jù)以及可能的操作失敗完全沒有提供檢查 找出程序中所有可能出錯(cuò)的地方 本練習(xí)中, 我們不關(guān)心可能會(huì)拋出的異常。
int *alloc_and_init( string file_name )
{
ifstream infile( file_name );
int elem_cnt;
infile >>elem_cnt;
int *pi = allocate_array( elem_cnt );
int elem;
int index = 0;
while ( cin >>elem )
pi[ index++ ] = elem;
sort_array( pi, elem_cnt );
register_data( pi );
return pi;
}
練習(xí) 2.19
alloc_and_init()函數(shù)會(huì)調(diào)用到下面的函數(shù) 如果這些函數(shù)調(diào)用失敗了 它們將拋出相應(yīng)類型的異常
allocate_array() noMem
sort_array() int
register_data() string
請(qǐng)?jiān)诤线m的地方插入一個(gè)或多個(gè) try 塊以及相應(yīng)的 catch 子句來處理這些異常 在 catch 子句中只需簡單地輸出錯(cuò)誤的出現(xiàn)情況
練習(xí) 2.20
檢查在練習(xí) 2.18 中的函數(shù) alloc_and_init()中所有可能出現(xiàn)的錯(cuò)誤 指出哪些錯(cuò)誤會(huì)拋出異常 修改該函數(shù) 或用練習(xí) 2.18 的版本 或用練習(xí) 2.19 的版本 來拋出對(duì)被識(shí)別的異常拋出文字串就可以了
練習(xí) 2.21
給出如下名字空間定義
namespace Exercise {
template
class Array { … };
template
void print( Array< Etype >);
class String { … };
template
class List { … };
}
以及下面的程序
int main() {
const int size = 1024;
Array< String >as( size )
54 第二章 C++瀏覽
List< int >il( size );
// …
Array< String >*pas = new Array(as);
List *pil = new List(il);
print( *pas );
}
同為類型名被封裝在名字空間中 所以當(dāng)前程序編譯失敗 把程序修改為
1 用限定名字修飾符來訪問名字空間 Exercise 中的類型定義
2 使用 using 聲明來訪問類型定義
3 用名字空間別名機(jī)制
4 用 using 指示符
練習(xí) 2.22
解釋每個(gè) vector 定義的結(jié)果
string pals[] = { “pooh”, “tigger”, “piglet”, “eeyore”,“kanga”};
(a) vector svec1( pals, pals+5);
(b) vector ivec1( 10 );
? vector ivec2( 10, 10 );
(d) vector svec2( svec1 );
(e) vector dvec;
練習(xí) 2.23
已知下列函數(shù)聲明 請(qǐng)實(shí)現(xiàn) min()的函數(shù)體 它查找并返回 vec 的最小元素 要求首先使用 索引 vec 中元素的 for 循環(huán) 來實(shí)現(xiàn) min() 然后 再使用 通過迭代器遍歷 vec 的 for 循環(huán) 來實(shí)現(xiàn) min() template
template
elemType
min( const vector &vec );
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購,新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧