一、做用域和可見性ios
1.1 函數原型中的參數其做用域僅在()內。所以參數名稱無關緊要,可是參數類型須要聲明。程序員
1.2 塊做用域 在塊中聲明的標識符其做用域自聲明處起,限於塊中。數組
1.3 類做用域 類做用域做用於特定的成員名。如類X的成員M具備類做用域,對M的訪問方式以下:函數
若是在X的成員函數中沒有聲明同名的局部做用標識符,那麼該函數內能夠訪問成員M; spa
經過表達式X.M或者X::M以及prt->M訪問。 指針
1.4 在全部類和函數以外出現的聲明,具備文件做用域,開始於聲明處,結束於文件結尾。code
二、可見性 可見性是從對標識符的引用的角度來講的,表示從內層做用域往外層做用域看的時候能看見什麼 對象
做用域: 文件做用域>類做用域>塊做用域blog
2.1 標識符聲明在前引用在後,若是某個標識符聲明在外層,且在內層沒有與之同名的標識符,則該標識符在內層可見;接口
2.2 對於兩個嵌套的做用域,若是在內層做用域內聲明瞭與外層做用域中同名的標識符,則外層做用域的標識符在內層不可見,也就是在內層被屏蔽。
#include <iostream> using namespace std; int i; //全局變量,文件做用域 int main() { i=5; //文件做用域的i賦初值 { //子塊1 int i; //局部變量,塊做用域 i=7; cout<<"i="<<i<<endl; //輸出7 } cout<<"i="<<i<<endl; //輸出5 }
三、對象的生存期 對象從產生到結束的這段時間。在對象生存期內,對象將保持其值,直到被更新。
3.1 靜態生存期與程序的運行期相同,在文件做用域中聲明的對象具備這種生存期,在函數內部聲明靜態生存期對象要冠以關鍵字static;
#include <iostream> using namespace std; int i; //全局變量,文件做用域 int main() { i=5; //文件做用域的i賦初值,具備靜態生存期 cout<<"i="<<i<<endl; //輸出5 return 0; }
3.2 動態生存期塊做用域中聲明的,沒有static修飾的對象,一般也稱爲局部生存期對象,開始於聲明點,結束於該標識符的做用域結束處。
#include<iostream.h> void fun(); int main() { fun(); fun(); } void fun()//靜態生存期對象a.第一次被調用a=1,i=5,運算以後a=2,i=6,第二次被調用時,因爲a具備靜態生存期,a的值保持不變,爲2,具備動態生存期的i已經被釋放,運算以後a=3,i=6。 { static int a=1; int i=5; a++; i++; cout<<"i="<<i<<",a="<<a<<endl; }
#include<iostream.h> int i=1; // i 爲全局變量,具備靜態生存期。 int main() { static int a;// 靜態局部變量,有全局壽命,局部可見。 int b=-10; // b, c爲局部變量,具備動態生存期。 int c=0; void other(void); cout<<"---MAIN---\n"; cout<<" i: "<<i<<" a: "<<a<<" b: "<<b<<" c: "<<c<<endl; c=c+8; other(); cout<<"---MAIN---\n"; cout<<" i: "<<i<<" a: "<<a<<" b: "<<b<<" c: "<<c<<endl; i=i+10; other(); } void other(void) { static int a=2; static int b; // a,b爲靜態局部變量,具備全局壽命,局部可見。 //只第一次進入函數時被初始化。 int c=10; // C爲局部變量,具備動態生存期, //每次進入函數時都初始化。 a=a+2; i=i+32; c=c+5; cout<<"---OTHER---\n"; cout<<" i: "<<i<<" a: "<<a<<" b: "<<b<<" c: "<<c<<endl; b=a; }
運行結果:
---MAIN---
i: 1 a: 0 b: -10 c: 0
---OTHER---
i: 33 a: 4 b: 0 c: 15
---MAIN---
i: 33 a: 0 b: -10 c: 8
---OTHER---
i: 75 a: 6 b: 4 c: 15
時鐘程序:
#include<iostream> using namespace std; class Clock //時鐘類定義 { public: //外部接口 Clock(); void SetTime(int NewH, int NewM, int NewS); //三個形參均具備函數原型做用域 void ShowTime(); ~Clock(){} private: //私有數據成員 int Hour,Minute,Second; }; //時鐘類成員函數實現 Clock::Clock() //構造函數 { Hour=0; Minute=0; Second=0; } void Clock::SetTime(int NewH, int NewM, int NewS) { Hour=NewH; Minute=NewM; Second=NewS; } void Clock::ShowTime() { cout<<Hour<<":"<<Minute<<":"<<Second<<endl; } Clock globClock; //聲明對象globClock,具備靜態生存期,文件做用域 // 由缺省構造函數初始化爲0:0:0 int main() //主函數 { cout<<"First time output:"<<endl; //引用具備文件做用域的對象globClock: globClock.ShowTime(); //對象的成員函數具備類做用域 //顯示0:0:0 globClock.SetTime(8,30,30); //將時間設置爲8:30:30 Clock myClock(globClock); //聲明具備塊做用域的對象myClock //調用拷貝構造函數,以globClock爲初始值 cout<<"Second time output:"<<endl; myClock.ShowTime(); //引用具備塊做用域的對象myClock //輸出8:30:30 }
四、數據與函數
能夠經過函數間的參數傳遞實現數據共享,更方便的將數據存儲在全局對象中,省去了傳遞的空間,若是將數據和使用數據的函數封裝在類中是面向對象的方法。
#include<iostream.h>//使用全局對象實現數據共享,可是使用全局變量會使得程序結構更復雜,並且牽一髮而動全身 int global; void f() { global=5;} void g() { cout<<global<<endl;} int main() { f(); g(); //輸出「5」 return 0; } #include<iostream.h>//將數據和函數封裝在類中實現數據共享 class Application { public: void f();void g(); private: int global; }; void Application::f() { global=5;} void Application::g() {cout<<global<<endl;} int main() { Application MyApp;//創建一個新對象來訪問函數,該對象彷佛不須要改對象,該處有點多餘,有待解決(靜態成員) MyApp.f(); MyApp.g(); return 0; }
五、靜態成員
靜態數據成員 用static聲明,屬於整個類的成員,並不須要經過對象去訪問。該類的全部對象維護該成員的同一個拷貝,必須在類外定義和初始化,用::來指明所屬的類。
靜態成員函數 類外代碼可使用類名和做用域操做符來調用靜態數據成員,靜態數據成員函數只能引用屬於該類的靜態數據成員或者靜態數據函數。
#include<iostream.h> class Application { public: static void f(); static void g(); private: static int global; }; int Application::global=0;//在類外初始化 void Application::f() { global=5;} void Application::g() {cout<<global<<endl;} int main() { Application::f();//不創建對象,直接經過類名來訪問。 Application::g(); return 0; }
注意事項:靜態成員數據和函數屬於整個類,不屬於任何對象,可是能夠經過對象來調用,也能夠經過類名來調用。
class A { public: static void f(A a); private: int x; }; void A::f(A a) { cout<<x; //對x的引用是錯誤的 cout<<a.x; //正確 } #include <iostream.h> class Point //Point類聲明 {public: //外部接口 Point(int xx=0,int yy=0){X=xx;Y=yy;countP++;} Point(Point &p);//拷貝構造函數 int GetX() {return X;} int GetY() {return Y;} static void GetC() {cout<<" Object id="<<countP<<endl;} private: //私有數據成員 int X,Y; static int countP; } Point::Point(Point &p) { X=p.X; Y=p.Y; countP++; } int Point::countP=0; int main() //主函數實現 { Point A(4,5); //聲明對象A cout<<"Point A,"<<A.GetX()<<","<<A.GetY(); A.GetC(); //輸出對象號,對象名引用 Point B(A); //聲明對象B cout<<"Point B,"<<B.GetX()<<","<<B.GetY(); Point::GetC(); //輸出對象號,類名引用 }
六、友元
友元是C++提供的一種破壞數據封裝和數據隱藏的機制,包括友元函數和友元類,是經過將一個模塊聲明爲另外一個模塊的友元,一個模塊就可以引用到另個模塊中本是被隱藏的信息,爲了確保數據的完整性和數據封裝與隱藏的原則,建議儘可能不使用或少使用友元。
友元函數是在類聲明中由關鍵字friend修飾說明的非成員函數,在它的函數體可以經過對象名訪問private和protected成員,增長了靈活性,使得程序員能夠在封裝和快速性方面作合理選擇,訪問對象中的成員必須經過對象名。
#include <iostream.h>//計算兩點距離 #include <math.h> class Point //Point類聲明 { public: //外部接口 Point(int xx=0, int yy=0) {X=xx;Y=yy;} int GetX() {return X;} int GetY() {return Y;} friend float Distance(Point &a, Point &b); //友元函數 private: //私有數據成員 int X,Y; }; double Distance( Point& a, Point& b) { double dx=a.X-b.X;//在類外經過對象直接訪問類point的私有數據成員 double dy=a.Y-b.Y; return sqrt(dx*dx+dy*dy); } int main() { Point p1(3.0, 5.0), p2(4.0, 6.0); double d=Distance(p1, p2); cout<<"The distance is "<<d<<endl; return 0; }
若一個類爲另外一個類的友元,則此類的全部成員均可以訪問對方類的私有成員,聲明語法:將友元類名在另個類使用friend修飾。
class A { friend class B;//友元類 public: void Display() {cout<<x<<endl;} private: int x; } class B { public: void Set(int i); void Display(); private: A a; }; void B::Set(int i)//能夠訪問並修改A類的私有成員 { a.x=i; } void B::Display() { a.Display(); }
注意事項:友元關係式單向的,若是聲明A是B的友元,B的成員函數能夠訪問A的私有和保護數據,可是反之否則。
七、共享數據的保護
常類型:常類型的對象必須初始化,並且不能被更新,實現對共享數據的保護。
常引用:被引用的對象不能被更新。 const 類型說明符 &引用名
常對象:必須進行初始化,不能被更新。類名 const 對象名
常數組:數組元素不能被更新。 類型說明符 const 數組名[大小]
常指針:指向常量的指針
用const修飾的對象成員
常成員函數:使用const說明,常成員函數不更新對象的數據成員,const是函數類型的一個組成部分,在實現函數的部分也要帶const關鍵字,const也能夠用於區分重載函數。經過對象只能調用它的常成員函數,不能經過常對象去調用普通數據函數。
#include<iostream> using namespace std; class R { public: R(int r1, int r2){R1=r1;R2=r2;} void print(); void print() const;//print函數的重載 private: int R1,R2; }; void R::print() { cout<<R1<<":"<<R2<<endl; } void R::print() const { cout<<R1<<";"<<R2<<endl; } int main() { R a(5,4); a.print(); //調用void print() const R b(20,52); //定義常對象來調用常成員函數print() b.print(); //調用void print() const } #include<iostream> using namespace std; class A { public: A(int i); void print(); const int& r;//常引用 private: const int a; static const int b; //靜態常數據成員 }; const int A::b=10; //靜態常數據成員在類外說明和初始化 A::A(int i):a(i),r(a) //常數據成員只能經過初始化列表來得到初值 { } void A::print() { cout<<a<<":"<<b<<":"<<r<<endl; } int main() { A a1(100),a2(0); a1.print(); a2.print(); }
八、編譯預處理命令
#include 包含指令 將一個源文件嵌入到當前源文件中該點處。
#include<文件名> 按標準方式搜索,文件位於C++系統目錄的include子目錄下
#include"文件名" 首先在當前目錄中搜索,若沒有,再按標準方式搜索。
#define 宏定義指令 定義符號常量,不少狀況下已被const定義語句取代。定義帶參數宏,已被內聯函數取代
#undef 刪除由#define定義的宏,使之再也不起做用。
條件編譯指令 #if 和 #endif
#if 常量表達式
//當「 常量表達式」非零時編譯
程序正文
#endif
......
條件編譯指令——#else
#if 常量表達式
//當「 常量表達式」非零時編譯
程序正文1
#else
//當「 常量表達式」爲零時編譯
程序正文2
#endif
條件編譯指令 #elif
#if 常量表達式1
程序正文1 //當「 常量表達式1」非零時編譯
#elif 常量表達式2
程序正文2 //當「 常量表達式2」非零時編譯
#else
程序正文3 //其餘狀況下編譯
#endif
條件編譯指令
#ifdef 標識符
程序段1
#else
程序段2
#endif
若是「標識符」經#defined定義過,且未經undef刪除,則編譯程序段1,不然編譯程序段2。
條件編譯指令
#ifndef 標識符
程序段1
#else
程序段2
#endif
若是「標識符」未被定義過,則編譯程序段1,不然編譯程序段2。
多文件結構
一個源程序能夠劃分爲多個源文件:
類聲明文件(.h文件)
類實現文件(.cpp文件)
類的使用文件(main()所在的.cpp文件)
利用工程來組合各個文件。
不使用條件編譯的頭文件
//main.cpp #include "file1.h" #include "file2.h" int main() { … } //file1.h #include "head.h" … //file2.h #include "head.h" … //head.h … class Point { … } …
使用條件編譯的頭文件
//head.h #ifndef HEAD_H #define HEAD_H … class Point { … } … #endif