天天看點

C++學習之資料的共享與保護

  • 辨別符的作用域與可見性

作用域是一個辨別符在程式正文中有效的區域。

作用域分類:

1、函數原型作用域

2、局部作用域(塊作用域)

3、類作用域。

4、檔案作用域。

5、命名空間作用域(後面會學習)

  • 函數原型作用域

函數原型中的參數,其作用域始于"(",結束于")"。

例如:

double area(double radius);
           
  • 局部作用域

函數的形參、在塊中聲明的辨別符。

其作用域自聲明處起,限于塊中。

例如:

void fun(int a) {
   int b = a;
   cin >> b;
   if (b > 0) {
     int c;
     ......
   }
}
           
  • 類作用域

類的成員具有類作用域,其範圍包括類體和非内聯成員函數的函數體。

如果在類作用域以外通路類的成員,要通過類名(通路靜态成員),或者該類的對象名、對象引用、對象指針(通路非靜态成員)。

  • 檔案作用域

不在前述各個作用域中出現的聲明,就具有檔案作用域,這樣聲明的辨別符其作用域開始于聲明點,結束于檔案尾。

  • 可見性

可見性是從對辨別符的引用的角度來談的概念。

可見性表示從内層作用域向外層作用域“看”時能看見什麼。

如果辨別在某處可見,就可以在該處引用此辨別符。

如果某個辨別符在外層中聲明,且在内層中沒有同一辨別符的聲明,則該辨別符在内層可見。

對于兩個嵌套的作用域,如果在内層作用域内聲明了與外層作用域中同名的辨別符,則外層作用域的辨別符在内層不可見。

例如:

//5_1.cpp
#include 
using namespace std;
 
int i;	//全局變量,檔案作用域
int main() { 
     i = 5; //為全局變量i指派
     {
         int i; //局部變量,局部作用域
         i = 7;
         cout << "i = " << i << endl;//輸出7
      }
      cout << “i = ” << i << endl;//輸出5
      return 0;
}
           
  • 對象的生存期

靜态生存期:

1、這種生存期與程式的運作期相同。

2、在檔案作用域中聲明的對象具有這種生存期。

3、在函數内部聲明靜态生存期對象,要冠以關鍵字static 。

動态生存期:

塊作用域中聲明的,沒有用static修飾的對象是動态生存期的對象(習慣稱局部生存期對象)。

開始于程式執行到聲明點時,結束于命名該辨別符的作用域結束處。

例如:

#include<iostream>
using namespace std;
int i = 1;         // i 為全局變量,具有靜态生存期。
void other() {
static int a = 2;
static int b;
// a,b為靜态局部變量,具有全局壽命,局部可見。
//隻第一次進入函數時被初始化。
int c = 10;     // C為局部變量,具有動态生存期,

//每次進入函數時都初始化。
a += 2; i += 32; c += 5;
cout<<"---OTHER---\n";
cout<<" i: "<<i<<" a: "<<a<<" b: "<<b<<" c: "<<c<<endl;
b = a;
}

int main() {
static int a;    //靜态局部變量,有全局壽命,局部可見。
int b = -10;     // b, c為局部變量,具有動态生存期。
int c = 0;
cout << "---MAIN---\n";
cout<<" i: "<<i<<" a: "<<a<<" b: "<<b<<" c: "<<c<<endl;
c += 8; other();
cout<<"---MAIN---\n";
cout<<" i: "<<i<<" a: "<<a<<" b: "<<b<<" c: "<<c<<endl;
i += 10; other();
return 0;
}
           

上面程式的運作結果是:

---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
           
  • 類的靜态成員

靜态資料成員:

1、用關鍵字static聲明。

2、為該類的所有對象共享,靜态資料成員具有靜态生存期。

3、必須在類外定義和初始化,用(::)來指明所屬的類。

例如:具有靜态資料成員的Point類:

C++學習之資料的共享與保護
#include <iostream>
using namespace std;

class Point {     //Point類定義
public:       //外部接口
       Point(int x = 0, int y = 0) : x(x), y(y) { //構造函數
           //在構造函數中對count累加,所有對象共同維護同一個count
           count++;
       }
       Point(Point &p) {    //複制構造函數
           x = p.x;
           y = p.y;
           count++;
       }

       ~Point() {  count--; }
       int getX() { return x; }
       int getY() { return y; }
       void showCount() {           //輸出靜态資料成員
           cout << "  Object count = " << count << endl;
       }

private:      //私有資料成員
       int x, y;
       static int count;       //靜态資料成員聲明,用于記錄點的個數
};

int Point::count = 0;//靜态資料成員定義和初始化,使用類名限定
int main() {       //主函數
       Point a(4, 5);     //定義對象a,其構造函數回使count增1
       cout << "Point A: " << a.getX() << ", " << a.getY();
       a.showCount(); //輸出對象個數
       Point b(a); //定義對象b,其構造函數回使count增1
       cout << "Point B: " << b.getX() << ", " << b.getY();
       b.showCount();       //輸出對象個數
       return 0;
}
           

程式的運作結果是:

Point A: 4, 5  Object count=1

Point B: 4, 5  Object count=2

  • 靜态函數成員

類外代碼可以使用類名和作用域操作符來調用靜态成員函數。

靜态成員函數主要用于處理該類的靜态資料成員,可以直接調用靜态成員函數。

如果通路非靜态成員,要通過對象來通路。

例如:具有靜态資料、函數成員的Point類:

C++學習之資料的共享與保護
#include <iostream>
using namespace std;

class Point {    
public:      
       Point(int x = 0, int y = 0) : x(x), y(y) {  count++; }//構造函數                  
       Point(Point &p) {    //複制構造函數
           x = p.x;
           y = p.y;
           count++;
       }

       ~Point() {  count--; }
       int getX() { return x; }
       int getY() { return y; }
       static void showCount() {   
       cout << "  Object count = " << count << endl;
       }

private:     
       int x, y;
       static int count;       //靜态資料成員聲明,用于記錄點的個數
};

int Point::count = 0;//靜态資料成員定義和初始化,使用類名限定

int main() {      
       Point a(4, 5);     //定義對象a,其構造函數回使count增1
       cout << "Point A: " << a.getX() << ", " << a.getY();
       Point::showCount();       //輸出對象個數
       Point b(a); //定義對象b,其構造函數回使count增1
       cout << "Point B: " << b.getX() << ", " << b.getY();
       Point::showCount();       //輸出對象個數
       return 0;
}

           
  • 類的友元

友元是C++提供的一種破壞資料封裝和資料隐藏的機制。

通過将一個子產品聲明為另一個子產品的友元,一個子產品能夠引用到另一個子產品中本是被隐藏的資訊。

可以使用友元函數和友元類。

為了確定資料的完整性,及資料封裝與隐藏的原則,建議盡量不使用或少使用友元。

友元函數:

友元函數是在類聲明中由關鍵字friend修飾說明的非成員函數,在它的函數體中能夠通過對象名通路 private 和protected成員

作用:增加靈活性,使程式員可以在封裝和快速性方面做合理選擇。

通路對象中的成員必須通過對象名。

例如:利用友元函數計算兩點之間的距離

#include <iostream>
#include <cmath>
using namespace std;

class Point { //Point類聲明
public: //外部接口
    Point(int x=0, int y=0) : x(x), y(y) { }
    int getX() { return x; }
    int getY() { return y; }
    friend float dist(Point &a, Point &b);
private: //私有資料成員
    int x, y;
};

float dist( Point& a, Point& b) {
    double x = a.x - b.x;
    double y = a.y - b.y;
return static_cast<float>(sqrt(x * x + y * y));
}

int main() {
    Point p1(1, 1), p2(4, 5);
    cout <<"The distance is: ";
    cout << dist(p1, p2) << 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.x=i;
}
void B::display() {
a.display();
};
           

類的友元關系是單向的:

如果聲明B類是A類的友元,B類的成員函數就可以通路A類的私有和保護資料,但A類的成員函數卻不能通路B類的私有、保護資料。

繼續閱讀