c++Primer筆記

筆記比較亂,得從下往上看,呵呵

 

打開一個僅用於輸出文件:ofstream outfile("copy.out",ios_base::out);//文件名,打開模式
ios_base::out 輸出模式  ios_base::app 附加模式,輸出模式打開已經存在的文件,則文件中的數

據將被丟棄,如果附加模式打開,新數據將添加在文件尾部,兩種模式中,如果文件不存在,程序會創建

一個新文件.
打開一個作爲輸入的文件:ifstream inFile("filename")
   outFile.puc(ch);     inFile.get(ch)
我們既可以用C風格字符數組的形式讀入字符串,也可以以string類類型的形式讀入字符串.string的

好處是與字符串相關的內存可被自動管理.

while( cin>> ival) 從標準輸入讀入一個序列,知道cin爲false爲止,有兩種情況會使一個istream

對象被計算爲false:讀到文件結束(在這種情況下,我們已經正確的讀完文件中所有的值)或遇到一個

無效的值,比如3.1515926
缺省情況下,所有空白符會丟掉,如果希望讀入空白符,或許是爲了保留原始的輸入格式,或者是爲了

處理空白符,一種方法是使用istream的get()(ostream對應put);

缺省情況下,false文字值被輸入爲0,而true被輸出爲1

max( int val1, int val2) { cout<<(val1 >val2)? val1:val2; }
則max(10,20)則輸出0,因爲<<的優先級高於?的有限級
正確的應爲:{ cout<<((val1 >val2)? val1:val2); }

在程序中使用iostream庫,必須包含相關的頭文件,如#include <iostream>
輸入輸出操作是有istream(輸入流)和ostream(輸出流)類提供的,iostream是同時從istream和

ostream派生,允許雙向輸入/輸出.爲了方便,這個庫定義了三個標準流對象:

(用戶終端的讀寫操作)
cin:代表標準輸入的istrem對象,使我們能夠從用戶終端讀入數據
cout:代表標準輸出的ostream對象,cout能使我們能夠向用戶終端寫數據.
cerr.

對文件的讀寫操作:include <fstream>
ifstream:從istream派生,把一個文件綁到程序上用來輸入.
ofstream:從ostream派生,把一個文件綁到程序上用來輸出.
fstream:從iostream派生,把一個文件綁到程序上用來輸入和輸出.
由於fstream頭文件中也包含了iostream頭文件,所以我們不需要同時包含這兩個文件

/*FILE *fp,*outf;
int ch;
while((ch=fgetc(fp))!=EOF)
{
cal[ch]++;
in_num++;
}
fclose(fp);*/
=====================================================================================
   重載的操作符在類體中被聲明,聲明方式同普通函數一樣,只不過他的名字包含關鍵字operator,

以及緊隨其後的一個預定義操作符.

類的初始化有一種可替換的方式:成員初始化表,是由逗號分開的成員名極其初值的列表.成員初始化

表只能在構造函數定義中被制定,而不是在其聲明中,該初始化表被放在參數表和構造函數體之間,由

冒號開始.

如果一個類聲明瞭一個包含多個參數的構造函數,但沒有聲明缺省構造函數,則每個類對象的定義都

必須提供所需的實參.在實踐中,如果定義了其他的構造函數,則也有必要提供一個缺省構造函數.

嵌套類:除非外圍類被聲明爲嵌套類的友元,否則他沒有權利訪問嵌套類的私有成員.嵌套類也沒有任

何特權訪問外圍類的私有成員,如果要授權,也必須把它聲明爲嵌套類的友元.

位域(bit-field):它可以被聲明存放特定數目的位,位域必須是有序數據類型,位於標識符後面跟一

個冒號,然後一個敞亮表達式制定位數.如:
typedef unsigned int Bit;
class File
{
public:
  Bit a:7;
  Bit b:8;
  Bit c:6;
}

聯合是一種特殊的類,一個聯合中的數據成員在內存中的存儲是互相重疊的,每個數據成員都在相同

的內存地址開始.分配給聯合的存儲區數量是"要包含它最大的數據成員"所需的內存數.

靜態成員函數訪問靜態數據成員

s2爲某類對象的指針 表達式 s2->height() 可以寫成 (*s2).height() 結果完全相同   

    一個友員或許是一個名字空間函數,另一個前面定義的類的一個成員函數,也可能是一個完整的

類.在使一個類成爲友員時,友員類的所有成員函數都被給予訪問"授權友誼類的非公有成員"的權利.

信息隱藏:
公有成員(public):在程序的任何地方都可以被訪問.
私有成員(private):只能被成員函數和類的[友元]訪問
保護成員(protected):對派生類就像public一樣,對其他程序則表現的像private.
默認的是private

除了靜態數據成員外,數據成員不能在類體中被顯式的初始化,如:class firts{ int meni=0;}
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
c++語言要求綁定在const vector上的iterator也必須是const iterator
const vector<int> vec; vector<type>::const_iterator iter=vec.begin();

拋出異常:在C++中,異常常常用類class來實現. 如class popOnEmpty();
throw popOnEmpty();//拋出異常是一個構造函數表達式
try 塊必須包圍能夠拋出異常的語句,try塊以關鍵字try開始,後面是花括號括起來的語句序列,在

try塊之後是一組處理代碼,被稱爲catch語句.
try{ ... } catch(pushOnFull){ ... }
           catch(popOnEmpty){ ... }
如果catch子句不包含返回語句,catch子句完成它的工作後,程序的執行將在CATCH子句列表的最後子

句之後繼續進行.C++的異常處理機制是不可恢復的,一旦異常被處理,程序的執行就不能夠在異常被

拋出的地方繼續.
-------------------------------------------------------------------------
422 int min(int (&r_array)[size]) { ... }
300
在C++中,數組永遠不會按值傳遞,它是傳遞第一個元素的指針.數組的長度不是參數類型的一部分,函

數不知道傳遞給它的數組的實際長度,一種常見的機制是提供一個含有數組長度的額外參數.

另外一種機制是將參數聲明爲[數組的引用],當參數爲一個數組類型的引用時,數組長度成爲參數和

實參類型的一部分,編譯器檢查數組實參的長度與在函數參數類型中指定的長度是否匹配.
例如:void putValue( int (&arr)[10] )

參數可以是多維數組,這樣的參數必須指明第一維以外的所有維的長度
例如:void putvalue( int matrix[][10],int rowsize)
int (*matrix)[10];//一個二維數組,每行由10個列元素構成
int *matrix[10]   //一個含有10個指向int的指針的數組
[]的優先級高於*
-------------------------------------------------------------------------
如果兩個函數的返回類型和參數表精確匹配,則第二個生命爲第一個的重複聲明.
函數的返回類型不足以區分兩個重載函數.

空類大小爲1;

標準C++庫中的所有組建都是在一個被稱爲std的名字空間中聲明和定義的.在標準頭文件(如

<vector>或<iostream>)中聲明的函數,對象和類模板,都被聲明在名字空間std中.名字空間std的成

員不能不加限定修飾訪問,最簡單的解決方案是在#include指示符後面加上using指示符如下:
using namespace std;

常量對象的動態分配:const int *pci=new const int(1024);//必須初始化,前後必須都有const

C風格字符串 char *str="123456789"長度爲9,實際佔用空間爲10,都以空字符結尾,所以要複製的時

候要多申請一個字節的空間,sizeof=10 ;strlen=9;
char *str2= new char[strlen(str)+1];否則會發生內存錯誤
strcpy(str2,str);

申請動態二維數組:
int **pi=new int*[m];
for(int i=0; i<m; i++)
pi[i]=new int[n];

for(i=0; i<m; i++)
delete [] pi[i];
delete [] pi;

三個指針常見錯誤:
 1.應用delete表達式失敗,使內存無法返回空閒存儲區,稱爲內存泄漏.(memory leak)
 2.對同一內存應用了兩次delete表達式.通常發生在兩個指針指向同一個動態分配對象的時候.通過

某個指針釋放對象,該對象的內存返回給空閒存儲區,然後又被分配給某個別的對象,接着指向舊對象

的第二個指針被釋放,新對象也就跟着消失了.
 3.delete後,指針沒設置爲0;

if(pi != 0) delete pi;  //沒必要,如果指針操作數被設置爲0,則C++會保證delete表達式不會調

用操作符delete(),所以沒必要測試其是否爲0.
空閒指針是程序錯誤的一個根源,很難被檢測到,一個較好的方法是在指針指向的對象被釋放後,將該

指針設置爲0,這樣可以清楚的表明該指針不再指向任何對象.
    delete表達式只能應用在指向的內存是用new表達式從[空閒存儲區[分配的指針上, 將delete表

達式應用在指向空閒存儲區以外的內存的指針上,會使程序運行期間出現未定義的行爲.
如:int i=8; int *pi=&i;  delete pi;//不安全,pi指向i,是一個局部對象,運行會發生內存錯誤
    int *pi2=new int(9); delete pi2;//安全

動態分配的對象被分配在程序的[空閒存儲區的內存池]中.空閒存儲區的一個特點是,氣宗分配的對

象沒有名字,new表達式沒有返回實際分配的對象,而是返回指向該對象的指針,對該對象的全部操作

都要通過這個指針間接完成.第二個特點是分配的內存是未初始化的,空閒存儲區的內存包含隨機的

位模式,它是程序運行前該內存上次使用留下的結果.
因爲空閒存儲區是有限的資源,所以當我們不再需要已分配的內存時,就應該馬上將其返還給該空閒

存儲區,這是很重要的.

在局部域中的變量聲明中引入了局部對象,有三種局部對象:自動對象(automatic object),寄存器對

象(register object),局部靜態對象(local static object)
    自動對象的存儲分配發生在定義它的函數被調用時,分配給自動變量的存儲區來自於[程序的運

行棧],它是函數的活動記錄的一部分.未初始化的自動對象包含一個隨機的位模式,是該存儲區上次

被使用的結果,它的值是爲指定的.函數結束時,它的活動記錄被從運行棧中彈出,與該自動對象關聯

的存儲區被真正的釋放.
    在函數中頻繁被使用的自動變量可以用regester聲明.如果可能的話,編譯器會把該對象裝載到

機器的寄存器中,如果不能夠的話,則該對象仍位於內存中.
for( register int ix=0; ix<sz; ++ix);
   把局部對象聲明爲static,把對象在整個程序運行期間一直存在的局部對象,當一個局部變量的值

必須在多個函數調用之間保持有效時,我們不能使用普通的自動對象,自動對象的值在函數結束時被

丟棄,可以聲明爲static,靜態局部變量對象被程序自動初始化爲0; 
void fuc() { static int depth; }


extern爲聲明但不定義一個對象提供了一種方法,該方法承諾了該對象在其他地方被定義:或者在此

文本文件的其他地方,或者在程序的其它文本文件中,例如 extern int i;關鍵字extern也可以 在函

數聲明中指定.

名字解析期間查找域的順序由內向外,所以在外圍域中聲明被嵌套域中的同名聲明所隱藏.

用來區分名字含義的一般上下文就是域(scope),C++支持三種形式的域:局部域(local scope),名字

空間域(namespace scope),類域(class scope).
名字解析是把表達式中的一個名字與某一個聲明想關聯的過程.

函數參數的類型不能是函數類型,函數類型的參數將被自動轉換爲該函數類型的指針.

int sort(string*, string*, int (*)(const string &, const string &));
等價與 typedef int (*PFI2S)(const string &, const string &);
       int sort(string*, string*, PFI2S);

        int(*testCases[10]) ();//函數指針數組
等價於: tepedef int(*PFV)();
        PFV testCases[10];

函數指針初始化和賦值: int lexicoCompare(const string &s1, const string &s2) { ... }
函數名lexicoCompare被解釋成 int (*)(const string &, const string &)的指針,將取址操作符

作用在函數名上也能產生指向該函數類型的指針,因此lexicoCompare AND &lexicoCompare類型相同

,指向函數的指針可以如下初始化:
   int (*pfi)  (const string &, const string &) = lexicoCompare;
OR int (*pfi2) (const string &, const string &) = &lexicoCompare;
只有當複製操作符左邊指針的參數表和返回類型與右邊函數或指針的參數表和返回類型完全匹配時,

初始化和賦值纔是正確的.
應用函數指針時,用 pf(ia,size) OR (*pf)(ia,size) 而不能用 *pf(ia,size);

函數指針:函數名不是其類型的一部分,函數的類型只由它的返回值和參數表決定.
int  *pf  (const string &, const string &); NO
int (*pf) (const string &, const string &); YES

實際上,命令行選項是main()實參
int mian(int argc, char *argv[]) { ... }
argc:命令行選項的個數,argv包含argc個C風格字符串,代表了由空格分割的命令選項.argv[0]總是

被設置爲當前正被調用的命令,從索引1到argc-1表示被傳遞給命令的實際選項.

*************************************************************************
調用函數有一個嚴重的缺點:調用函數比直接計算要慢的多,不但必須拷貝實參,保存機器的寄存器,

程序還必須轉向一個新位置.內聯函數(inline)函數給出了一個解決方案.它將在程序中的每個調用

點上被"內聯地"展開. 一個遞歸函數不能在調用點完全展開(雖然第一個調用可以),一個大的函數也

不太可能在調用點展開,一般的,inline機制用來優化小的,只有幾行的,經常被調用的函數.

爲了替換一個大型的參數表,程序員可以將參數聲明爲類(或結構體),數組或某一容器類型,這樣的參

數可以用來包含一組參數值.類似的情況,一個函數只能返回一個值,如果程序要求返回多個值,那麼

程序員可以將某些函數參數聲明爲引用,這樣,函數可以直接修改實參,或者可以聲明一個函數,它的

返回類型是一個可以包含一組返回值的類或某一種容器類型.

一個程序中各種函數通過兩種機制進行通信,一種方法是使用全局對象,另一種方法是使用函數參數

表和返回值.

缺省情況下,函數的返回值是按值傳遞的.局部對象的生命期隨函數的結束而結束,在函數結束後,該

引用變成未定義的內存的別名.在這種情況下,返回類型應該被聲明爲非引用類型,然後在局部對象的

生命週期結束之前拷貝局部變量.
函數返回一個左值,對返回值的任何修改都將改變被返回的實際對象

省略號參數:當我們無法列出傳遞給函數的所有實參的類型和數目,這時我們可以使用省略號(...)指

定函數參數表.省略號掛起類型檢查機制,它的出現告知編譯器,當函數被調用時,可以有0個或多個實

參,而實參的類型位置,兩種形式:void foo(para_list,...)  void foo(...);
for example: int printf( const char* ...)

缺省實參:函數聲明可以全部或部分參數制定缺省實參,在左邊參數的任何缺省實參被提供之前,最右

邊未初始化參數必須被提供缺省實參.這是由於函數調用的實參是按照位置來解析的.
         int ff(int a, int b, int c=0)
重新聲明:int ff(int a, int b=0, int c)

指針,引用的區別:引用必須初始化爲指向一個對象,一旦初始化了,它就不能再指向其它對象,而指針

可以指向一系列不同的對象也可以什麼也不指向.引用參數的一個重要用法是,它允許我們有效的實

現操作符重載的同時,還能保證用法的直觀性.
    因爲指針可以指向一個對象或者沒有任何對象,所以函數在確定指針實際指向一個有效的對象之

前不能安全的解引用(dereference)一個指針.所以在使用指針作爲參數時,我們必須首先判斷指針是

否爲空 ptr == 0 OR ptr == NULL

如果要修改指針本身,而不是指針引用的對象,那麼可以聲明一個參數,該參數是一個指針引用
如:void ptrswap(int *&v1, int *&v2){}

函數要想操作實參,就用指針傳遞或者引用傳遞,不能用值傳遞

for循環內部定義的對象的可視性侷限在for循環體內,外部訪問非法,WHILE循環也一樣

在if(condition)中condition中定義的對象,旨在與if相關的語句或語句塊兒中可見.試圖在if語句

後面訪問會導致編譯錯誤.

字符在進行算數運算是取其ASC碼,如 'a'爲97; 3+'a'=100

C++在運算前自動進行算數轉換,以便在計算前轉換成相同的類型,轉換規則是小類型總是被提升爲大

類型,以防精度損失.

&:按位與  &&:邏輯與;  >>移位操作必須有左值,否則會返回去,例如 a>>3;A右移了3位,輸出A時還

是原值,要實現移動效果 A= A>>3;也可以實現整數位移,如 5<<8;//5左移8位

逗號表達式是一系列由逗號分開的表達式,這些表達式從左向右計算,結果是最右邊表達式的值

系統爲每個程序提供了一個在程序執行時可用的內存池.這個可用的內存池被稱爲程序的 空閒存儲

區 或 堆.運行時刻的內存分配被稱爲動態內存分配.

SIZEOF()一個對象或者類型名的字節長度,應用在數組上時,返回整個數組的字節長度

數組標識符代表數組中第一個元素的地址,*IA相當於IA[0],*(IA+1)相當於IA[1]

字符串(常量)包含一個額外的終止空字符

非CONST變量不能被用來指定數組的維數

如果有必要,算術值和指針值也能隱式的轉換成BOOL類型的值,0或空指針被轉換成FALSE,所有的其它

值都被轉換成TRUE;

引用主要被用作函數的形式參數,通常將類對象傳遞給一個參數.

const對象的地址只能賦值給const對象的指針,但是指向const對象的指針可以被賦以一個非const對

象的地址,而且該非const對象不能通過const指針改變.

INT *P=0; 空指針

字符串被存儲在一個字符數組中,一般通過一個 CHAR* 類型的指針來操縱它

任何人如果事先不知道指針是否有值,都應該先行測試,然後纔對指針進行操作

如果我們要做的僅僅是持有地址值(可能把一個地址同令一個地址比較),那麼指針的實際類型就不重

要了.C++提供了一種特殊的指針來支持這種需求:空類型指針(VOID*),它可以被任何數據指針類型的

地址值賦值.不能操作空類型指針所指向的對象.

指針:爲清楚起見,最好寫成  int *x  而不是  int*  x;
int * x,y;X是指針,而Y則不是

右值:被讀取的值 左值:位置值

字符文字前加L表示寬字符文字,如L'a',寬字符常量用來支持某些語言的字符集合,如漢語

整數文字常量可以被寫成十進制,八進制,十六進制,但這不會改變整數值的位序列.
string類型支持通過下標操作符訪問單個字符

判斷字符串是否結束: *str++;不結束爲TRUE,結束時爲FALSE
WHILE( *STR++) COUT<<*STR;   最後STR指針指向該字符串的後一個地址,要正確使用需要返回!(參

考STRCPY)
指針爲空,則str=0

20 023,0X14,在整形文字常量後加L,將其指定爲LONG整形.加U將其指定爲一個無符號數

迭代器是一個支持指針類型抽象的類對象

  一般來說,當兩個或多個函數重複相同的代碼時,就會將這部分代碼抽取出來,形成獨立的函數,以

便共享,以後,如果需要改變這些實現,則只需改變一次.

    函數調用比直接訪問內存的開銷要大的多;內聯函數在他的調用點上被展開,類定義中被定義的

函數會被自動當作是內斂函數

int *pint=new int(12);//分配指針指向一個整形,賦初值爲12  delete pint;
int *pia= new int[4]; //分配一個4個整數元素的數組        delete [] pia;

C++中,指針的主要作用是管理和操作動態分配的內存

防止一個頭文件被多次包含:
#ifndef BOOKSTORE_H
#define BOOKSTORE_H

Bookstore.h內容

#endif

程序中用 #ifdef  #endif來判斷一個預處理器變量是否已被定義
------------------------------------------------------------------
文件輸入輸出:#include <fstream>
ofstream outfile("out_file")
ifstream infile("in_file")
infile>>a;
outfile<<a;

數組之間不能直接複製 如 A=B,數組不知道自己的長度

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章