在前面1-5篇中詳細(xì)講解一些類的示例卷仑,其中每個對象都有自己的數(shù)據(jù)成員數(shù)據(jù)集仗岸。 該類的每個成員函數(shù)都可以訪問其類的任何對象的任何成員茁瘦。在某些情況下涝焙,可能希望定義可以由該類的所有實例都能訪問的公共數(shù)據(jù)字段。在C中也遇到這種情況距潘,C源文件中的幾個函數(shù)需要訪問同一變量炼列。 C的一種常見解決方案是同個源文件中定義所有函數(shù),并且定義一個static變量.在源文件之外音比,變量名不可見俭尖。 這種方法非常有效,但是違反了我們在每個源文件中僅使用一個函數(shù)的原則。
C ++通過定義靜態(tài)成員來解決該問題:這些靜態(tài)成員是類的所有對象所共有的數(shù)據(jù)和函數(shù)稽犁,并且(在私有部分中定義時)在類外部無法訪問焰望。 這些靜態(tài)成員是本章的主題。
靜態(tài)成員不能定義為virtual函數(shù)已亥。 虛擬成員函數(shù)是普通成員熊赖,因為它具有this指針。 由于靜態(tài)成員函數(shù)沒有此指針虑椎,因此無法將其聲明為virtual秫舌。
靜態(tài)數(shù)據(jù)
類的任何數(shù)據(jù)成員都可以聲明為static; 無論是在類接口的public部分還是private部分中绣檬。 與為該類的每個對象一次又一次創(chuàng)建的非靜態(tài)數(shù)據(jù)成員相反,此類數(shù)據(jù)成員僅創(chuàng)建和初始化一次嫂粟。
程序啟動后立即創(chuàng)建靜態(tài)數(shù)據(jù)成員娇未。 即使它們是在程序執(zhí)行周期的最開始創(chuàng)建的,它們?nèi)匀皇瞧漕惖恼嬲蓡T星虹。為了方便區(qū)分靜態(tài)數(shù)據(jù)成員和普通數(shù)據(jù)成員建議為靜態(tài)數(shù)據(jù)成員的名稱加上s_前綴零抬。
公共靜態(tài)數(shù)據(jù)成員是全局變量。 程序的所有代碼都可以訪問它們宽涌,只需使用其類名平夜,范圍解析運算符及其成員名即可。以下是詳細(xì)的例子:
類接口:cone.hh文件
#include <string>
class Cone
{
std::string d_name;
double d_radius;
double d_height;
double d_busLength;
public:
static double s_pi;
static int s_count;
Cone(std::string, double, double);
//計算體積
double volume();
//計算底面面積
double bottom_area();
//計算表面積
double surface_area();
//計算側(cè)面積
double side_area();
//顯示容積
void display_volume();
};
如果沒有其他初始化卸亮,則在創(chuàng)建第一個對象時忽妒,所有靜態(tài)數(shù)據(jù)都會根據(jù)其聲明的數(shù)據(jù)類型進(jìn)行類內(nèi)默認(rèn)值初始化。
靜態(tài)數(shù)據(jù)成員的初始化:不能將其放在類接口中兼贸,一般來說,公共的靜態(tài)數(shù)據(jù)成員是放在類接口外部進(jìn)行初始化段直,方法是使用作用域運算符::來重新聲明靜態(tài)變量,以標(biāo)識它屬于哪個類溶诞,下面是一個很貼切的例子。
類實現(xiàn):cone.cpp文件
#include "../header/cone.hh"
#include <iostream>
#include <math.h>
// 靜態(tài)成員在類接口外初始化
int Cone::s_count = 0;
double Cone::s_pi = 3.14;
Cone::Cone(std::string name, double r, double h) : d_radius(r), d_height(h), d_name(name)
{
s_count++;
std::cout << "創(chuàng)建一個錐體,目前數(shù)量是" << s_count << std::endl;
if (d_radius > 0 && d_height > 0)
{
d_busLength = sqrt(d_radius * d_radius + d_height * d_height);
}
}
inline double Cone::volume()
{
return s_pi * d_radius * d_radius * d_height / 1000 / 3.0;
}
inline void Cone::display_volume()
{
std::cout << "錐體"<<d_name<<"的容積是" << volume() << "L" << std::endl;
}
double Cone::side_area()
{
//公式PI*R*L
return s_pi * d_radius * d_busLength;
}
inline double Cone::surface_area()
{
return side_area() + bottom_area();
}
inline double Cone::bottom_area()
{
//公式:PI*R*R
return s_pi * d_radius * d_radius;
}
調(diào)用代碼:
int main(int argc, char const *argv[])
{
Cone c1 = {"N1", 43.5, 72.5};
Cone c2 = {"N2", 52.77, 23.33};
Cone c3 = {"N3", 47.5, 72.5};
Cone c4 = {"N4", 32.77, 33.33};
c1.display_volume();
c2.display_volume();
c3.display_volume();
c4.display_volume();
return 0;
}
而實際項目中,我們更傾向于將整個項目的所有類的靜態(tài)數(shù)據(jù)成員集中在某個源文件當(dāng)中(例如:st_data.cpp),然后在程序入口的源文件include這個st_data.cpp就可以了。
由于構(gòu)造函數(shù)是為類的每個新對象調(diào)用的猫妙,因此構(gòu)造函數(shù)不會初始化靜態(tài)數(shù)據(jù)成員串绩。 最多就是修改。 原因是靜態(tài)數(shù)據(jù)成員在調(diào)用該類的任何構(gòu)造函數(shù)之前就已經(jīng)存在枉圃。 定義靜態(tài)數(shù)據(jù)成員時功茴,在任何成員函數(shù)之外都將對其進(jìn)行初始化,就像對普通(非類)全局變量的初始化一樣孽亲。
靜態(tài)成員函數(shù)
除了靜態(tài)數(shù)據(jù)成員痊土,C ++還允許我們定義靜態(tài)成員函數(shù)。與類的所有對象共享的靜態(tài)數(shù)據(jù)類似墨林,靜態(tài)成員函數(shù)的特征如下赁酝。
-
靜態(tài)成員函數(shù)可以訪問其類的所有靜態(tài)成員犯祠,也可以訪問其類的對象的成員(包括private或public),但
前提要指定一個該類的對象
. - 靜態(tài)成員函數(shù)并沒與其類的任何對象關(guān)聯(lián),因此它們沒有this指針酌呆。
- 靜態(tài)成員函數(shù)只能從類外部訪問靜態(tài)數(shù)據(jù)成員衡载,其他靜態(tài)成員函數(shù)和任何其他函數(shù)。
- 靜態(tài)成員函數(shù)可以被在類接口的public部分聲明的其他靜態(tài)成員函數(shù)調(diào)用隙袁,而無需指定其類的對象痰娱。以下示例說明了靜態(tài)成員函數(shù)的這種特征:
下面的示例是為了上面的靜態(tài)成員函數(shù)的特征的,我們在前文的Cone類接口中增加兩個靜態(tài)成員函數(shù)的聲明
類接口
class Cone{
.....
//顯示側(cè)面面積
static void display_sideArea(Cone &);
//顯示表面積
static void display_surfArea(Cone &);
}
類實現(xiàn)
很多情況下:我們可能需要用靜態(tài)成員函數(shù)菩收,調(diào)用它所屬的類的某個實例的非靜態(tài)數(shù)據(jù)成員 梨睁, 正是特征1所說的那樣。特征2和3更不用說了娜饵,下面這些示例都是從類外調(diào)用的
void Cone::display_sideArea(Cone &obj)
{
std::cout << obj.d_name << "側(cè)面積:" << obj.side_area() << std::endl;
}
void Cone::display_surfArea(Cone &obj)
{
std::cout << obj.d_name << "表面積:" << obj.surface_area() << std::endl;
}
下面是靜態(tài)成員函數(shù)調(diào)用同一個類的靜態(tài)函數(shù)坡贺,正如上面特征4所述
void Cone::display_all(Cone &obj)
{
std::cout << "型號:" << obj.d_name << std::endl;
std::cout << "參數(shù):"
<< "r " << obj.d_radius << " h " << obj.d_height << " l " << obj.d_busLength << std::endl;
display_surfArea(obj);
display_sideArea(obj);
}
調(diào)用代碼
#include "./cone.cpp"
#include <iostream>
using namespace std;
int main(int argc, char const *argv[])
{
Cone c1 = {"N1", 43.5, 72.5};
Cone c2 = {"N2", 52.77, 23.33};
Cone c3 = {"N3", 47.5, 72.5};
Cone c4 = {"N4", 32.77, 33.33};
c1.display_volume();
c2.display_volume();
c3.display_volume();
c4.display_volume();
Cone::display_sideArea(c1);
Cone::display_surfArea(c2);
Cone::display_all(c1);
Cone::display_all(c2);
return 0;
}