1.先看以下代碼:
#include <iostream>
using namespace std;
class Base
{
static int itest;
public:
void Set()
{
itest++;
}
void Show()
{
cout << itest << endl;
}
};
int Base::itest = 100;
class Derive: public Base
{
};
class Derive2: public Base
{
};
int _tmain(int argc, _TCHAR* argv[])
{
Derive d1;
Derive2 d2;
d1.Set();
d2.Set();
d1.Show();
d2.Show();
return 0;
}
輸出是:
102
102
我以前的了解既然Derive和Derive2是從Base派生的兩個不同的類,那麼他們從Base繼承而來的static變量也應該是不同的兩份拷貝。是以他們應該輸出
101
101
而不是實際上的102.
唉,出現這樣的錯誤看來還是自己的c++基礎太差了。其實對于類的static成員變量它不單獨屬于任何派生類,static成員隻存在一份。所有派生類包括基類均共享這唯一的一份。是以才出現了開始的輸出結果。
2. 下面的程式更加證明了我的錯誤:
#include <iostream>
using namespace std;
class Base{
static int itest;
public:
void Set(){
itest++;
}
void Show(){
cout << itest << endl;
}
};
int Base::itest = 100;
class Derive: public Base
{
};
class Derive2: public Base
{
};
int _tmain(int argc, _TCHAR* argv[])
{
Derive d1;
Derive2 d2;
cout << sizeof(Base) <<endl;
cout << &(Base::itest) << endl;
cout << sizeof( Derive ) << endl;
cout << &(Derive::itest) << endl;
cout << sizeof( Derive2) << endl;
cout << &(Derive2::itest) << endl;
return 0;
}
程式輸出結果表明Base和Derive以及Derive2的大小都是1. 這個結果表明Base類的static成員變量并未包含在任何一個類空間中。
3.然而對于定義static變量的類有些時候我們還是希望每個從其派生出來的類都能包含單獨的一份拷貝而不是與基類和其他派生類共享。 能不能實作這樣的想法呢?
答案是肯定的。
先看以下代碼然後我在做解釋:
#include <iostream>
using namespace std;
template< typename _class >
class Base{
static int itest;
public:
void Set(){
itest++;
}
void Show(){
cout << itest << endl;
}
};
template < typename _class >
int Base< _class >::itest = 100;
class Derive: public Base<Derive>{
};
class Derive2: public Base<Derive2>{
};
int _tmain(int argc, _TCHAR* argv[])
{
Derive d1;
Derive2 d2;
d1.Set();
d2.Set();
d1.Show();
d2.Show();
return 0;
}
輸出:
101
101
這次的輸出是101,正是我想要的結果。為什麼呢?
原因是這裡用到了模闆,我們用不同的參數Base<Derive>、Base<Derive2>去執行個體化了這個模闆,這就意味着Derive和Derive2派生自兩個完全不同的類。因而避開了先前讨論的問題。
模闆Base中定義的類型參數在Base中并沒有實際的用到,他存在的唯一價值就是為我們提供了辨別Base類的機會。也就是我們可以通過指定不同的類型參數而從同一個模闆得到完全不同的兩個類型定義。
4. 注意在類中不能對static資料成員進行初始化,要初始化的話必須在類外進行定義!注意,static資料成員不是通過類構造函數進行初始化的!如上面的代碼所示:在類外定義int Person::age=20;這裡前面就不要再加static了。如果類中有多個static資料成員,static資料成員初始化的次序是按照static資料成員在類中的聲明次序進行初始化的,初始化了之後,就可以使用static資料成員了,我們可以通過作用域操作符從類直接調用static資料成員,或者通過對象,引用,或指向該類類型對象的指針間接調用(這種情況下static資料成員必須是public的通路權限,如果定義在private通路權限下是不行的)。
說到static資料成員,有一種情況不得不提,那就是特殊的const static成員。如上面所述,類的static成員,像普通資料成員一樣,不能在類的定義體中進行初始化。隻能在類外進行初始化。const int 型的static成員便可以在類定義體内部進行初始化。記住一定隻能是const int型的,換成const string ,double都不行的。看下面這段代碼:
#include <iostream>
#include <string>
using namespace std;
class Person
{
private:
string name;
static const int age=20;
static string address;
public:
Person(const string&nm):name(nm)
{}
static string Address()
{
return address;
}
void Print()
{
cout<<name<<" is "<<age ;
}
};
string Person::address="Beijing";
static.cpp檔案
#include "stdafx.h"
#include "static.h"
#include <iostream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
Person person("tom");
person.Print();
cout<<" and live in "<<person.Address();
cout<<endl;
return 0;
}
隻有age才能在類定義體内進行初始化,address是不行的。
5. static成員的所有者是類本身和對象,但是多有對象擁有一樣的靜态成員。進而在定義對象是不能通過構造函數對其進行初始化。
靜态成員不能在類定義裡邊初始化,隻能在class body外初始化。
靜态成員仍然遵循public,private,protected通路準則。
靜态成員函數沒有this指針,它不能傳回非靜态成員,因為除了對象會調用它外,類本身也可以調用。
出現在類體外的函數定義不能指定關鍵字static;
靜态成員之間可以互相通路,包括靜态成員函數通路靜态資料成員和通路靜态成員函數;
非靜态成員函數可以任意地通路靜态成員函數和靜态資料成員;
靜态成員函數不能通路非靜态成員函數和非靜态資料成員;