C++與Java中的static成員總結

簡述

在結構化程序設計中,內存中數據的共享是通過參數, 全局變量實現的;
在面向對象程序設計中函數與數據成員封裝在一起, 數據共享通過類內部數據成員之間的相互訪問, 外部對象則通過靜態成員(即static成員)來共享數據;
接下來通過面向對象敘述static特性

C++中的static

靜態成員
使用關鍵字static修飾的函數/數據成員, 靜態成員屬於整個類, 由同一個類的所有對象所擁有,共享; 一般通過類名進行訪問: 類名::標識符 ;
注: 在類中定義靜態數據成員, 僅僅是對靜態數據成員進行引用性聲明, 必須在類外使用類名限定定義性聲明(即真正的聲明),這時才能進行初始化

#include<iostream>
using namespace std;
class A{
    public:
        static int count;
        A(){
            ++count; 
            cout<<"構造函數"<<endl; 
        }
        A(A const& a){
            ++count; 
            cout<<"複製構造函數"<<endl;   
        }
        ~A(){cout<<"析構函數"<<endl;
            count--; 
        }
        static int show(){
            return count; //靜態成員函數可以直接訪問該類的靜態數據成員,訪問費靜態數據成員只能通過對象名
        } 

};
int A::count=0; 
void f(){//順帶測試一下靜態生存期
    static int j=0; 
    j+=2;
    int i=2;
    cout<<i<<" static j="<<j<<endl;
    i+=2; 
}
int main(){
    f();
    cout<<"A對象個數"<<A::show()<<endl;//還沒有構造對象的時候,count數爲0
    A a;
    A b=a;//發生複製構造 
    A c(b);
    A d;
    cout<<"A對象個數"<<A::count<<endl; //此時count數爲4
    cout<<endl;
    f(); 
    return 0; 
} 

此處做着重說明: 靜態函數不能是虛函數, 虛函數用於動態綁定(通過虛表的索引值進行函數地址的查找, 索引值必須用到this, 所以靜態函數函數不能作爲虛函數)
爲何static成員函數不能爲virtual
1. static成員不屬於任何類對象或類實例,所以即使給此函數加上virutal也是沒有任何意義的。
2. 靜態與非靜態成員函數之間有一個主要的區別。那就是靜態成員函數沒有this指針。
虛函數依靠vptr和vtable來處理。vptr是一個指針,在類的構造函數中創建生成,並且只能用this指針來訪問它,因爲它是類的一個成員,並且vptr指向保存虛函數地址的vtable.
對於靜態成員函數,它沒有this指針,所以無法訪問vptr. 這就是爲何static函數不能爲virtual.
虛函數的調用關係:this -> vptr -> vtable ->virtual function

第二點: 對const成員函數設置爲靜態沒有任何意義, const只是對函數的this指針進行限制, 而靜態函數沒有this指針

Java中的static

Java中的靜態變量(類變量): static修飾, 主要用於修飾類成員方法, 加載優先於對象初始化(static成員在類被加載的時候就被加載了, 加載static成員會優先於), 靜態代碼塊優先於構造方法執行, 被所有對象共享

  • 整個類中只有一個值
  • 類初始化的同時就被賦值
  • 適用於所有類對象都具有的相同屬性,經常需要共享的數據, 系統中的常量值
  • 引用格式: 類名.變量名(或者靜態函數名)

靜態方法: 類方法,屬於當前類, 調用直接類名.靜態方法(), 只能是外部靜態數據成員, 靜態方法中不可出現this關鍵字; 靜態方法中不能訪問非靜態成員(包含屬性, this,super, 非靜態方法); 原因在於當前對象未構造, 無屬性,this,super存在, 但是反之即可(對象都創建了, 肯定能訪問)
例:

public class test{
    public static void main(String[] args){
        System.out.println(A.show());
        A a1=new A();
        A a2=new A();
        A a3=new A();
        System.out.println(A.show());
    }
}
class A{
        public static int i=0;
        public A(){i++; System.out.println("構造方法");}
        public static int show(){return i;}
}
//結果將顯示0 3,表示構造3個對象

靜態方法調用非靜態時引發的錯誤

public class test{
    public void info(){
        System.out.println("一般方法");
    }
    public static void main(String[] args){
        info();
    }
}

上述操作將出現錯誤靜態上下文引用非靜態變量, main()方法爲static, 當main方法初始化的時候, 對象還未創建, 調用info的對象是this, this還未被創建,對上述操作有如下改進

public static void main(String[] args){
    new test().info();
}

注: 當涉及到super時, 效果與this一致;

總結

C++與Java中的static用法具有區別, 但是核心都是static只屬於類, 靜態函數不能調用非靜態變量(包含this,super, 一般成員函數,成員變量), 最主要的原因還是在於this的隱藏, 大多數的出現的靜態調用非靜態主要在於this,super以及在對象還未產生就調用對象的函數

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章