1. 程式人生 > 其它 >C++友元和繼承

C++友元和繼承

友元函式
原則上,不能從宣告它們的同一類外部訪問該類的私有成員和受保護成員。但是,此規則不適用於“朋友”。

友元是用friend關鍵字宣告的函式或類。

如果非成員函式被宣告為該類的朋友,則該非成員函式可以訪問該類的私有成員和受保護成員。這是通過在類中包含此外部函式的宣告並在其前面加上關鍵字來完成的friend:

// friend functions
#include <iostream>
using namespace std;

class Rectangle {
    int width, height;
  public:
    Rectangle() {}
    Rectangle (
int x, int y) : width(x), height(y) {} int area() {return width * height;} friend Rectangle duplicate (const Rectangle&); }; Rectangle duplicate (const Rectangle& param) { Rectangle res; res.width = param.width*2; res.height = param.height*2; return res; } int main () { Rectangle foo;
Rectangle bar (2,3); foo = duplicate (bar); cout << foo.area() << '\n'; return 0; }

24

該duplicate函式是類的朋友Rectangle。因此,functionduplicate能夠訪問type的不同物件的成員width和height(是私有的)Rectangle。請注意,儘管在宣告中duplicate或main函式以後使用中,函式均不duplicate視為類的成員Rectangle。不是!它只是沒有成員就可以訪問其私有成員和受保護成員。

朋友功能的典型用例是在兩個不同類之間進行的操作,這些類訪問二者的私有或受保護成員。

友元類
與朋友功能類似,朋友類是一個類,其成員可以訪問另一個類的私有或受保護成員:

// friend class
#include <iostream>
using namespace std;

class Square;

class Rectangle {
    int width, height;
  public:
    int area ()
      {return (width * height);}
    void convert (Square a);
};

class Square {
  friend class Rectangle;
  private:
    int side;
  public:
    Square (int a) : side(a) {}
};

void Rectangle::convert (Square a) {
  width = a.side;
  height = a.side;
}
  
int main () {
  Rectangle rect;
  Square sqr (4);
  rect.convert(sqr);
  cout << rect.area();
  return 0;
}

16

在此示例中,classRectangle是class的朋友,Square允許其Rectangle成員函式訪問的私有成員和受保護成員Square。更具體地說,Rectangle訪問成員變數Square::side,該變數描述正方形的側面。

此示例中還有一些新內容:在程式的開頭,有一個空的class宣告Square。這是必需的,因為classRectangle使用Square(作為member中的引數convert)並Square使用Rectangle(將其宣告為朋友)。

除非特別說明,否則永遠不會建立友誼:在我們的示例中,“”Rectangle不將友誼視為朋友類Square,而,則不將Square視為朋友Rectangle。因此,成員函式Rectangle可以訪問的受保護成員和私有成員,Square但不能相反。當然,Square也可以將其宣告為的朋友Rectangle,如果需要,可以授予此類訪問許可權。

友誼的另一個特性是,它們不是可傳遞的:除非明確指定,否則朋友的朋友不會被視為朋友。

類之間的繼承
可以擴充套件C ++中的類,建立保留基類特徵的新類。這個過程稱為繼承,它涉及一個基類和一個派生類:派生類繼承了基類的成員,並且可以在其基礎上新增自己的成員。

例如,讓我們想象一系列描述兩種多邊形的類:矩形和三角形。這兩個多邊形具有某些共同的屬性,例如計算它們的面積所需的值:可以使用高度和寬度(或底數)簡單地描述它們。

在類的世界中可以用一個類Polygon來表示,我們可以從中得到另外兩個類:Rectangle和Triangle:
在這裡插入圖片描述

該Polygon班將包含成員是兩種型別的多邊形常見。在我們的情況下:width和height。並且Rectangle並且Triangle將是其派生類,它們的特定特徵與一種多邊形不同。

從其他派生的類繼承基類的所有可訪問成員。這意味著,如果基類包含一個成員,A並且我們從該類派生出一個帶有另一個成員B的類,則該派生類將同時包含memberA和member B。

在派生類中聲明瞭兩個類的繼承關係。派生類定義使用以下語法: 哪裡是派生類的名稱,以及

class derived_class_name: public base_class_name
{ // };

derived_class_namebase_class_name是它所基於的類的名稱。該public訪問說明符可以由其他任何一個訪問說明符(protected或private)代替。此訪問說明符限制了從基類繼承的成員的最大訪問級別:具有更高訪問級別的成員將繼承此級別,而具有相等或更高限制訪問級別的成員將其限制級別保留在派生類中。 。

// derived classes
#include <iostream>
using namespace std;

class Polygon {
  protected:
    int width, height;
  public:
    void set_values (int a, int b)
      { width=a; height=b;}
 };

class Rectangle: public Polygon {
  public:
    int area ()
      { return width * height; }
 };

class Triangle: public Polygon {
  public:
    int area ()
      { return width * height / 2; }
  };
  
int main () {
  Rectangle rect;
  Triangle trgl;
  rect.set_values (4,5);
  trgl.set_values (4,5);
  cout << rect.area() << '\n';
  cout << trgl.area() << '\n';
  return 0;
}

20
10

的類的物件Rectangle和Triangle每一個都包含從繼承的成員Polygon。它們是:width,height和set_values。類中使用

的protected訪問說明符Polygon與相似private。唯一的區別實際上是在繼承方面發生的:當一個類繼承另一個類時,派生類的成員可以訪問從基類繼承的受保護成員,但不能訪問其私有成員。

通過宣告width和height作為protected代替private,這些成員還從派生類訪問Rectangle和Triangle,而不是僅僅從成員Polygon。如果它們是公開的,則可以從任何地方訪問它們。

我們可以根據哪些功能可以通過以下方式訪問它們來總結不同的訪問型別:
在這裡插入圖片描述

“非成員”表示從類外部進行的任何訪問,例如從main,從另一個類或從函式進行的訪問。

在上面的示例中,由繼承Rectangle並Triangle具有與其基類相同的訪問許可權的成員Polygon:

Polygon::width           // protected access
Rectangle::width         // protected access

Polygon::set_values()    // public access
Rectangle::set_values()  // public access  

這是因為已經public在每個派生類上使用關鍵字聲明瞭繼承關係:

class Rectangle: public Polygon { /* ... */ }

這public在冒號之後的關鍵字(:)表示最容易到達的水平從它後面(在這種情況下,類繼承的成員Polygon)將具有從所述派生類(本例中Rectangle)。因為public是最易訪問的級別,所以通過指定此關鍵字,派生類將繼承具有與基類相同級別的所有成員。

使用protected,繼承基類的所有公共成員,就像protected在派生類中一樣。相反,如果指定了最嚴格的訪問級別(private),則所有基類成員都將繼承為private。

例如,如果女兒是從母親派生的課程,我們將其定義為:

class Daughter: protected Mother;

這將被設定protected為其Daughter從母親繼承的成員的限制性較低的訪問級別。也就是說,是所有成員public在Mother將成為protected中Daughter。當然,這不會限制Daughter宣佈自己的公共成員。這限制較少的訪問級別時,才設定從繼承的成員Mother。

如果沒有為繼承指定訪問級別,則編譯器將對用關鍵字宣告的類假定為私有,對於用宣告的類假定為class公共struct。

實際上,大多數C ++繼承用例都應使用公共繼承。當基類需要其他訪問級別時,通常可以更好地將它們表示為成員變數。

從基類繼承什麼?
原則上,公共派生類繼承對基類每個成員的訪問許可權,但以下情況除外:

它的建構函式和它的解構函式
其分配運算子成員(operator =)
它的朋友
它的私人成員

即使沒有繼承繼承對基類的建構函式和解構函式的訪問許可權,但派生類的建構函式和解構函式也會自動呼叫它們。

除非另有說明,否則派生類的建構函式將呼叫其基類的預設建構函式(即,不帶引數的建構函式)。可以使用與初始化列表中的成員變數相同的語法來呼叫基類的其他建構函式: 例如:

derived_constructor_name (parameters) : base_constructor_name (parameters) {...}
// constructors and derived classes
#include <iostream>
using namespace std;

class Mother {
  public:
    Mother ()
      { cout << "Mother: no parameters\n"; }
    Mother (int a)
      { cout << "Mother: int parameter\n"; }
};

class Daughter : public Mother {
  public:
    Daughter (int a)
      { cout << "Daughter: int parameter\n\n"; }
};

class Son : public Mother {
  public:
    Son (int a) : Mother (a)
      { cout << "Son: int parameter\n\n"; }
};

int main () {
  Daughter kelly(0);
  Son bud(0);
  
  return 0;
}

Mother: no parameters
Daughter: int parameter

Mother: int parameter
Son: int parameter

注意建立Mother新Daughter物件時呼叫哪個建構函式與作為物件時呼叫哪個建構函式之間的區別Son。所不同的是,由於不同建構函式宣告Daughter和Son:

Daughter (int a)          // nothing specified: call default constructor
Son (int a) : Mother (a)  // constructor specified: call this specific constructor 

多重繼承
一個類可以從一個以上的類中繼承,只需在一個類的基類列表中(即,在冒號之後)簡單指定多個用逗號分隔的基類即可。例如,如果程式有一個特定的類要在螢幕上列印,稱為Output,並且我們希望我們的類Rectangle並Triangle繼承其成員,那麼Polygon我們可以編寫以下內容:

class Rectangle: public Polygon, public Output;
class Triangle: public Polygon, public Output; 

這是完整的示例:

// multiple inheritance
#include <iostream>
using namespace std;

class Polygon {
  protected:
    int width, height;
  public:
    Polygon (int a, int b) : width(a), height(b) {}
};

class Output {
  public:
    static void print (int i);
};

void Output::print (int i) {
  cout << i << '\n';
}

class Rectangle: public Polygon, public Output {
  public:
    Rectangle (int a, int b) : Polygon(a,b) {}
    int area ()
      { return width*height; }
};

class Triangle: public Polygon, public Output {
  public:
    Triangle (int a, int b) : Polygon(a,b) {}
    int area ()
      { return width*height/2; }
};
  
int main () {
  Rectangle rect (4,5);
  Triangle trgl (4,5);
  rect.print (rect.area());
  Triangle::print (trgl.area());
  return 0;
}

20
10