本文記錄我對c++ PRimer以及Introduction to programming with c++關(guān)于靜態(tài)成員這一節(jié)的學(xué)習(xí)
基本概念
靜態(tài)成員
從形式上來說,用static關(guān)鍵字聲明的變量或者函數(shù)就是靜態(tài)成員。它可以是public或者是private。對數(shù)據(jù)類型也沒有過多的限制。 從意義上理解來說,靜態(tài)成員是這樣的一種成員:與類保持關(guān)聯(lián)而不與類的對象保持關(guān)聯(lián)。也即,類的靜態(tài)成員存在于任何對象之外,而對象中也不包含任何與靜態(tài)數(shù)據(jù)成員有關(guān)的數(shù)據(jù)。
簡言之,靜態(tài)成語是屬于類的,而不屬于每一個對象。
靜態(tài)成員函數(shù)不能用const進行修飾
由于靜態(tài)成員函數(shù)不與任何對象綁定在一起,所以他們不包含this指針。作為結(jié)果,靜態(tài)成員函數(shù)不能聲明成const。 這句話怎么理解?兩個角度:其一,const所修飾的成員函數(shù)的語義是,該函數(shù)不修改對象的屬性。也就是說,const所修飾的函數(shù)一定是和對象相關(guān)的。但是靜態(tài)成員函數(shù)由于本省不與任何對象綁定,本省也無法修改對象屬性,所以談不到用const修飾。其二,const修飾的成員函數(shù),我的理解是const本質(zhì)是對this的限制,從而讓this所指向的對象為常量,從而無法修改。但是,由于靜態(tài)成員不含有this指針,所以沒有使用const的必要。
簡言之,const所修飾的成員函數(shù)一定是和對象相關(guān)的,但是靜態(tài)成員是屬于類的,和對象無關(guān),所以沒有const修飾的必要。
定義靜態(tài)成員和初始化
因為靜態(tài)成員不屬于類的任何對象,所以它并不是在類的對象創(chuàng)建時被定義的。因此,類的構(gòu)造函數(shù)不用對靜態(tài)成員的初始化負責(zé)。必須在類的外部定義和初始化靜態(tài)成員。對于類的成員函數(shù)則可以在類的內(nèi)部或者外部定義,只是類外定義不能使用static,并且由于沒有this指針,所以無法訪問類的非靜態(tài)變量。 簡言之,對于靜態(tài)數(shù)據(jù)成員,初始化一定是在類外,成員函數(shù)均可。
靜態(tài)成員的類內(nèi)初始化
靜態(tài)數(shù)據(jù)成員一般是在外部初始化,但是有一個例外是。當(dāng)這個靜態(tài)數(shù)據(jù)成員本生是常量的時候。可以在類內(nèi)初始化。如下代碼:
#include <iostream>#include <cstring>class A{public: A(){std::memset(arr, 0, sizeof(arr));} void input(){ for(int i = 0; i < maxn; ++i){ std::cin >> arr[i]; } } void output() const { for(int i = 0; i < maxn; ++i){ std::cout << arr[i] << " "; } std::cout << std::endl; }private: static const int maxn = 8;// 靜態(tài)常量,類內(nèi)初始化 int arr[maxn];};int main( void ){ A a; a.output(); a.input(); a.output(); return 0;}靜態(tài)成員有某些特殊的應(yīng)用場景,而普通成員不行 c++ primer主要講了兩個點:
靜態(tài)成員可以是不完全類型,但是普通成員則不行。當(dāng)然,指針成員也可以靜態(tài)成員可以作為默認實參,普通成員不行。注意 雖然,靜態(tài)成員不與對象關(guān)聯(lián),我們一般是通過類去調(diào)用它們。但是,這并不影響它作為類的成員在其他成員函數(shù)當(dāng)中使用。只是需要知道,靜態(tài)成員函數(shù)不能訪問類的成員變量,但是類的非靜態(tài)成員函數(shù),是可以訪問靜態(tài)成員變量的。畢竟他么也是成員變量。
下面給出一個綜合實例:
代碼
CircleWithStaticDataFields.h#ifndef CIRCLE_H#define CIRCLE_H#include <cstring>class Circle{public: Circle(){std::memset(this, 0, sizeof(Circle)); ++number_of_objects; } Circle( double r ) : radius_(r) { ++number_of_objects; } double get_radius() const { return radius_; } void set_radius( double r ) { radius_ = r; } double get_area() const;public: static int get_number_of_objects(); // 靜態(tài)成員函數(shù)private: static double init_pi(); // 靜態(tài)成員函數(shù)private: double radius_;private: static int number_of_objects; // 靜態(tài)成員變量 static double PI; // 靜態(tài)成員變量};#endifCircleWithStaticDataFields.cpp#include "CircleWithStaticDataFields.h"#include <cmath>int Circle::get_number_of_objects(){ // 類外定義靜態(tài)成員函數(shù),不能使用static return Circle::number_of_objects;}double Circle::init_pi(){ return std::atan(1.0)*4;}int Circle::number_of_objects = 0; // 類外對靜態(tài)數(shù)據(jù)成員初始化double Circle::PI = Circle::init_pi(); // 雖然init_pi()是私有函數(shù),也可用來初始化靜態(tài)成員。畢竟還是在類的作用域內(nèi)double Circle::get_area() const{ return Circle::PI * radius_ * radius_;}main.cpp#include "CircleWithStaticDataFields.h"#include <iostream>int main( void ){ std::cout << "Number of circle objects created: " << Circle::get_number_of_objects() << std::endl; Circle circle1; std::cout << "The area of the circle of the radius " << circle1.get_radius() << " is " << circle1.get_area() << std::endl; std::cout << "Number of circle objects created: " << Circle::get_number_of_objects() << std::endl; Circle circle2(1.0); std::cout << "The area of the circle of the radius " << circle2.get_radius() << " is " << circle2.get_area() << std::endl; std::cout << "Number of circle objects created: " << Circle::get_number_of_objects() << std::endl; Circle circle3(3.3); std::cout << "The area of the circle of the radius " << circle3.get_radius() << " is " << circle3.get_area() << std::endl; std::cout << "Number of circle objects created: " << Circle::get_number_of_objects() << std::endl; std::cout << "circle1.get_number_of_objects() returns " << circle1.get_number_of_objects() << std::endl; // Circle::get_number_of_objects() 這種是建議寫法,讀者能輕易知道這是靜態(tài)成員函數(shù) std::cout << "circle2.get_number_of_objects() returns " << circle2.get_number_of_objects() << std::endl; return 0;}