1. 程式人生 > >C++語言--友元類與巢狀類-8.1----友元類、巢狀類

C++語言--友元類與巢狀類-8.1----友元類、巢狀類

前言:C++系列到此結束。終於可以寫點簡單的Jni了。感謝自己的努力!!! 友元是一種允許非類成員函式訪問類的非公有成員的一種機制。可以把一個函式指定為類的友元,也可以把整個類指定為另一個類的友元 1.友元類

一、友元介紹
我們知道,類的成員函式可以訪問同類的其他成員函式,包括公有、私有和保護成員。而類的外部函式只能訪問類的公有成員。

友元是一種允許非類成員函式訪問類的非公有成員的一種機制。
可以把一個函式指定為類的友元,也可以把整個類指定為另一個類的友元。

友元函式
友元類

二、友元函式
友元函式在類作用域外定義,但它需要在類體中進行說明
為了與該類的成員函式加以區別,定義的方式是在類中用關鍵字friend說明該函式,格式如下:

friend  型別 友元函式名(引數表);
友元的作用在於提高程式的執行效率

友元函式注意事項:
1、
友元函式不是類的成員函式,在函式體中訪問物件的成員,必須用物件名加運算子“.”加物件成員名。但友元函式可以訪問類中的所有成員(公有的、私有的、保護的),一般函式只能訪問類中的公有成員。

2、友元函式不受類中的訪問許可權關鍵字限制,可以把它放在類的公有、私有、保護部分,但結果一樣。

3、某類的友元函式的作用域並非該類作用域。如果該友元函式是另一類的成員函式,則其作用域為另一類的作用域,否則與一般函式相同。

4、友元函式破壞了面向物件程式設計類的封裝性,所以友元函式如不是必須使用,則儘可能少用。或者用其他手段保證封裝性。

程式碼如下:
#include <math.h>
#include <iostream>
using namespace std;
class Point
{
    friend double Distance(const Point &p1, const Point &p2);
public:
    Point(int x, int y);
private:
    int x_;
    int y_;
};
Point::Point(int x, int y) : x_(x), y_(y)
{
}
double Distance(const Point &p1, const Point &p2)
{
    double dx = p1.x_ - p2.x_;
    double dy = p1.y_ - p2.y_;
    return sqrt(dx * dx + dy * dy);
}
int main(void)
{
    Point p1(3, 4);
    Point p2(6, 9);
    cout << Distance(p1, p2) << endl;
    return 0;
}


程式中Distance 是Point類的友元函式,可以訪問類的私有資料成員。

三、友元類
如果某類B的成員函式會頻繁的存取另一個類A的資料成員, 而A的資料成員的Private/Protectd限制造成B存取的麻煩, B只能通過A的Public的成員函式進行間接存取
把B做成A類的友元類,即A類向B類開放其Private/Protectd內容, 讓B直接存取
友元類:一個類可以作另一個類的友元
友元類的所有成員函式都是另一個類的友元函式
友元類的宣告:
friend class 類名;

友元類注意事項:
1、友元關係是單向的
2、友元關係不能被傳遞
3、友元關係不能被繼承

TeleController.h :

程式碼如下:

#ifndef  _TELE_CONTROLLER_H_
#define _TELE_CONTROLLER_H_
class Television;
class TeleController
{
public:
    void VolumeUp(Television &tv);
    void VolumeDown(Television &tv);
    void ChanelUp(Television &tv);
    void ChanelDown(Television &tv);
};
#endif // _TELE_CONTROLLER_H_ 



TeleController.cpp :
程式碼如下:
#include "TeleController.h"
#include "Television.h"
void TeleController::VolumeUp(Television &tv)
{
    tv.volume_ += 1;
}
void TeleController::VolumeDown(Television &tv)
{
    tv.volume_ -= 1;
}
void TeleController::ChanelUp(Television &tv)
{
    tv.chanel_ += 1;
}
void TeleController::ChanelDown(Television &tv)
{
    tv.volume_ -= 1;
} 


Television.h:
程式碼如下:
#ifndef _TELEVISION_H_
#define _TELEVISION_H_
class TeleController;
class Television
{
    friend class TeleController;
public:
    Television(int volume, int chanel);
private:
    int volume_;
    int chanel_;
};
#endif // _TELEVISION_H_



Television.cpp:
程式碼如下:
#include "Television.h"
Television::Television(int volume, int chanel) : volume_(volume), chanel_(chanel)
{
} 



main.cpp:
程式碼如下:
#include "Television.h"
#include "TeleController.h"
#include <iostream>
using namespace std;
int main(void)
{
    Television tv(1, 1);
    TeleController tc;
    tc.VolumeUp(tv);
    return 0;
}



將TeleController 類作為Television類的友元類,這樣TeleController 類的成員函式就都可以訪問Television類的所有成員,包括私有
2.巢狀類

概念:

    所謂巢狀類,就是在類中宣告的類。如下程式碼中,類Inner就是一個巢狀類,類Outer是外圍類:

class Outer
{
    class Inner
    {
        std::string m_strInner;
    };

    std::string m_strOuter;
};


可見性:

巢狀類對於外圍類:

  1. 巢狀類僅僅是宣告在外圍類內部的型別,而不是外圍類的成員

  2. 外圍類不具備巢狀類所定義的成員

  3. 對於外圍類來說,巢狀類和其他的類沒有任何區別;外圍類能訪問巢狀類物件的public成員,不能訪問巢狀類物件的protected及private成員

外圍類對於巢狀類:

  1. 巢狀類不具備外圍類所定義的成員

  2. 巢狀類能訪問外圍類的public成員,不能訪問外圍類的protected及private成員

巢狀類對於外圍類外部的作用域:

  1. 無論巢狀類宣告為public、protected還是private,巢狀類對於外圍類任何成員可見

  2. 當巢狀類在外圍類中宣告為public時,對外圍類之外的作用域可見,外圍類之外的作用域可通過“::”訪問巢狀類;

    • 以下程式碼正確無誤,輸出“I an inner”

    • #include <iostream>
      #include <string>
      
      class Outer
      {
      public:
          class Inner
          {
          public:
              Inner():m_strInner("I an inner")
              {
              }
      
              void PrintInner()
              {
                  printf("%s", m_strInner.c_str());
              }
          private:
              std::string m_strInner;
          };
      };
      
      int main(void)
      {
          Outer::Inner inner;
          inner.PrintInner();
      
          getchar();
          return 0;
      }


  3. 當巢狀類在外圍類中宣告為protected或private時,對外圍類之外的作用域不可見

    • 以下程式碼編譯錯誤

    • include <iostream>
      #include <string>
      
      class Outer
      {
          class Inner
          {
          public:
              Inner():m_strInner("I an inner")
              {
              }
      
              void PrintInner()
              {
                  printf("%s", m_strInner.c_str());
              }
          private:
              std::string m_strInner;
          };
      };
      
      int main(void)
      {
          Outer::Inner inner;
          inner.PrintInner();
      
          getchar();
          return 0;
      }


繼承性:

  1. 下面列出了巢狀類在基類中三種訪問屬性和繼承的三種方式共9總組合,繼承之後巢狀類在派生類中的訪問屬性

  2. 結合1和上文的“可見性”就可得出當派生類作為巢狀類的外圍類,巢狀類和外圍類之間,巢狀類和外圍類之外的作用域之間的可見性了;這裡就不一一列舉,留給讀者自己去驗證