14.5 Statyczne funkcje składowe

Funkcje składowe klasy mogą być zadeklarowane jako statyczne. Takie funkcje można wywołać nawet wtedy, gdy nie istnieje jeszcze żaden obiekt klasy. Do ich nazwy z zewnątrz klasy odwołujemy się poprzez nazwę klasy za pomocą operatora zasięgu, czyli „czterokropka” (' ::'), albo za pomocą operatora wyboru składowej (kropka) — nie ma wtedy znaczenia, jakiego obiektu tej klasy użyjemy. Ponieważ funkcja statyczna nie jest wywoływana na rzecz obiektu, ale jak funkcja globalna, nie można w niej odwoływać się do this ani do żadnych składowych niestatycznych — te bowiem istnieją tylko wewnątrz konkretnych obiektów i w każdym z nich mogą być różne. Można natomiast w funkcjach statycznych klasy odwoływać się do składowych statycznych tej klasy: innych funkcji statycznych i zmiennych klasowych (określanych przez statyczne pola klasy).

Funkcje statyczne klasy od funkcji zadeklarowanych w zasięgu globalnym różni to, że należą do zakresu (przestrzeni nazw) klasy. Mają zatem bezpośredni dostęp do nazw z zakresu tej klasy (również prywatnych).

Na przykład program acc.cpp może być przepisany w następujący sposób, tym razem z funkcją obliczającą iloczyn skalarny jako funkcją statyczną:


P103: memstat.cpp     Składowe funkcje statyczne

      1.  #include <iostream>
      2.  using namespace std;
      3.  
      4.  class Vector {
      5.      double x, y, z;
      6.  public:
      7.      void set(double xx = 0, double yy = 0, double zz =0) {
      8.          x = xx;
      9.          y = yy;
     10.          z = zz;
     11.      }
     12.      static double dot_product(const Vector& w1,
     13.                                const Vector& w2) {
     14.          return w1.x * w2.x + w1.y * w2.y + w1.z * w2.z;
     15.      }
     16.  };
     17.  
     18.  int main() {
     19.      Vector w1, w2, ww;
     20.      w1.set(1, 1, 2);
     21.      w2.set(1,-1, 2);
     22.  
     23.      cout << "w1*w2 = "
     24.           << Vector::dot_product(w1, w2) << endl;  
     25.  
     26.      cout << "w1*w2 = "
     27.           << ww.dot_product(w1, w2)      << endl;  
     28.  }

Zauważmy wywołanie z linii  poprzez kwalifikację nazwą klasy i wywołanie z linii , gdzie funkcja jest wywoływana formalnie na rzecz obiektu ww, choć w rzeczywistości żadna informacja o tym obiekcie nie zostanie do funkcji przekazana (nie był on nawet sensownie zainicjowany!). Obiekt ww został użyty wyłącznie do tego, aby określić klasę w której zasięgu określona jest nazwa funkcji; równie dobrze mogliśmy tu użyć dowolnego innego obiektu klasy Vector. Cała informacja o wektorach które mają być pomnożone jest przekazywana przez argumenty.

T.R. Werner, 25 lutego 2017; 22:31