Üye fonksiyonlarında statik değişkenler


158

Birisi üye işlevlerindeki statik değişkenlerin C ++ 'da nasıl çalıştığını açıklayabilir.

Aşağıdaki sınıf verildiğinde:

class A {
   void foo() {
      static int i;
      i++;
   }
}

Birden çok örneğini Abildirirsem foo(), bir örnekte çağırma itüm örneklerde statik değişkeni artırır mı? Yoksa sadece onun çağrıldığı mı?

Her örnek kendi kopyasını olurdu i, ancak bazı kod üzerinden adım aksi belirtmek gibi görünüyor.

Yanıtlar:


169

Çünkü class Aşablon olmayan bir sınıf ve A::foo()şablon olmayan bir işlevdir. static int iProgramın içinde yalnızca bir kopya olacaktır .

ANesnenin herhangi bir örneği aynı etkiyi etkiler ive programın ömrü boyunca ikalır. Bir örnek eklemek için:

A o1, o2, o3;
o1.foo(); // i = 1
o2.foo(); // i = 2
o3.foo(); // i = 3
o1.foo(); // i = 4

3
İyi örnek için teşekkürler! static int iÖrneğe özgü kapsamı ortaya koyan bir şey elde etmenin bir yolu var mı , yani o1.foo(); // i = 1ve $o2.foo(); // i = 1...?
Stingery

14
Bu, aradığınız stil olmasa da, i'yi özel bir A sınıfının üyesi yapmak, tanımladığınız etkiye sahip olacaktır. Ad çakışmaları konusunda endişeleriniz varsa m_, i'nin durumunu belirtmek gibi bir önek ekleyebilirsiniz .
Carl Morris

137

Anahtar kelime staticmaalesef C ++ 'da birkaç farklı ilişkisiz anlama sahiptir.

  1. Veri üyeleri için kullanıldığında, verilerin örneklerde değil sınıfta tahsis edildiği anlamına gelir .

  2. Bir fonksiyon içindeki veriler için kullanıldığında, verilerin statik olarak tahsis edildiği, blok ilk kez girildiğinde başlatıldığı ve program sonlanıncaya kadar sürdüğü anlamına gelir . Ayrıca değişken yalnızca işlevin içinde görülebilir. Yerel statikin bu özel özelliği genellikle tekil tembel yapıları uygulamak için kullanılır.

  3. Bir derleme birimi düzeyinde (modül) kullanıldığında, değişkenin genel (yani tahsis edilmeden önce başlatılır mainve çalıştırılır ve imha edilir main) olduğu , ancak değişkenin diğer derleme birimlerinde erişilebilir veya görünmeyeceği anlamına gelir .

Her kullanım için en önemli olan bölüme biraz önem verdim. Kullanım (3), dışa aktarılmamış sınıf bildirimlerine de izin veren adsız ad alanları lehine bir şekilde cesaret kırılmıştır.

Kodunuzda staticanahtar kelime 2 anlamı ile kullanılır ve sınıflar veya örneklerle ilgisi yoktur ... bu işlevin bir değişkeni ve yalnızca bir kopyası olacaktır.

Doğru şekilde iammilind'in söylediği gibi , işlev bir şablon işlevi olsaydı, bu değişkenin birden çok örneği olabilir (çünkü bu durumda aslında fonksiyonun kendisi programdaki birçok farklı kopyada mevcut olabilir). Bu durumda bile sınıflar ve örnekler ilgisizdir ... aşağıdaki örneğe bakın:

#include <stdio.h>

template<int num>
void bar()
{
    static int baz;
    printf("bar<%i>::baz = %i\n", num, baz++);
}

int main()
{
    bar<1>(); // Output will be 0
    bar<2>(); // Output will be 0
    bar<3>(); // Output will be 0
    bar<1>(); // Output will be 1
    bar<2>(); // Output will be 1
    bar<3>(); // Output will be 1
    bar<1>(); // Output will be 2
    bar<2>(); // Output will be 2
    bar<3>(); // Output will be 2
    return 0;
}

41
+1 keyword static unfortunately has a few different unrelated meanings in C++:)
iammilind

Dünya bunu okuduktan sonra çok daha mantıklı, TEŞEKKÜR EDERİZ
Erin

Şablonlarla olan hileyi seviyorum. Kullanmak için bir bahane bulmak için sabırsızlanıyorum.
Tomáš Zato - Monica'yı eski durumuna getir

Herkes "isimsiz ad alanları lehine cesaret kırıldı" için bir referans var mı?
austinmarton

3
@austinmarton: C ++ programında "Yerel çeviri birimine" belirtmek için statik kullanımı C ++ 'da kullanımdan kaldırıldı. Bunun yerine adlandırılmamış ad alanlarını kullan (8.2.5.1) ", sürümümdeki C ++ Programlama Dili'nde (10. baskı, Eylül 1999) sayfa 819.
6502

2

Fonksiyonlar içindeki statik değişkenler

  • Statik değişken, fonksiyonun yığında değil programın statik belleğinde saklanan bir fonksiyon içinde oluşturulur.

  • Statik değişken başlatma, fonksiyonun ilk çağrısında yapılacaktır.

  • Statik değişken, birden çok işlev çağrısında değeri koruyacaktır

  • Statik değişkenin ömrü Program'dır

resim açıklamasını buraya girin

Örnekler

#include <iostream>

using namespace std;

class CVariableTesting 
{
    public:
    
    void FuncWithStaticVariable();
    void FuncWithAutoVariable();

};

void CVariableTesting::FuncWithStaticVariable()
{
    static int staticVar = 0; //staticVar is initialised by 0 the first time
    cout<<"Variable Value : "<<staticVar<<endl;
    staticVar++;
}
void CVariableTesting::FuncWithAutoVariable()
{
    int autoVar = 0;
    cout<<"Variable Value : "<<autoVar<<endl;
    autoVar++;
}
    

int main()
{
    CVariableTesting objCVariableTesting;
    cout<<"Static Variable";
    objCVariableTesting.FuncWithStaticVariable();
    objCVariableTesting.FuncWithStaticVariable();
    objCVariableTesting.FuncWithStaticVariable();
    objCVariableTesting.FuncWithStaticVariable();
    objCVariableTesting.FuncWithStaticVariable();
    
    cout<<endl;
    cout<<"Auto Variable";
    objCVariableTesting.FuncWithAutoVariable();
    objCVariableTesting.FuncWithAutoVariable();
    objCVariableTesting.FuncWithAutoVariable();
    objCVariableTesting.FuncWithAutoVariable();
    objCVariableTesting.FuncWithAutoVariable();
    
    return 0;
}

Çıktı :

Statik Değişken

Değişken Değer: 0
Değişken Değer: 1
Değişken Değer: 2
Değişken Değer: 3
Değişken Değer: 4

Otomatik Değişken

Değişken Değer: 0
Değişken Değer: 0
Değişken Değer: 0
Değişken Değer: 0
Değişken Değer: 0


-2

Basitleştirilmiş cevap:

Statik değişkenler, bir (şablonlanmamış) classveya (şablon olmayan) işlevin üyesi olup olmadıklarına bakılmaksızın , teknik olarak, kapsamı classveya işleviyle sınırlı olan global bir etiket gibi davranırlar .


9
Hayır. Globaller program başlangıcında başlatılır, fonksiyon statikleri ilk kullanımda başlatılır. Bu büyük bir fark.
6502

Bunun olduğunu sanmıyorum. Ancak, bu yine de derleyiciye özgü olmalıdır.
0xbadf00d

2
O zaman yanlış düşünüyorsunuz: C ++ standardında 3.6.1, ad alanı kapsamındaki nesnenin statik depolama süresi ile oluşturulmasının başlangıçta gerçekleştiğini; 6.7 (4) genel olarak "... böyle bir değişken, kontrolün bildiriminden ilk kez geçtiğinde başlatılır; böyle bir değişken, başlatılmasının tamamlanmasının ardından başlatılmış sayılır". Bu arada, ilk kullanımda bu başlatma, tembel singleton yapısını uygulamak için çok kullanışlıdır.
6502

3.7.4: "Varsa, statik depolama süresine sahip bir blok kapsamı varlığının sürekli başlatılması (3.6.2), bloğunun ilk girilmesinden önce gerçekleştirilir. Bir uygulamanın diğer blok kapsamı değişkenlerinin erken başlatılmasına izin verilir. bir uygulamanın ad alanı kapsamındaki statik veya iş parçacığı depolama süresine sahip bir değişkeni statik olarak başlatmasına izin verilen aynı koşullar altında statik veya iş parçacığı saklama süresi (3.6.2).
0xbadf00d

1
Ancak merakla: 1) sürekli başlatma için bloğa ilk kez girmeden önce yerel bir statikin başlatılıp başlatılamayacağı tartışılmaz (değişken sadece blok içinde görülebilir ve sabit başlatma hiçbir yan etki oluşturmaz); 2) yayınınızda sürekli başlatma hakkında hiçbir şey söylenmez; 3) Yerel statikler, sabit olmayan başlatma için çok yararlıdır MyClass& instance(){ static MyClass x("config.ini"); return x; }- tek iplik kullanımı için geçerli bir taşınabilir uygulama, çünkü yerel statikler söylediklerinize rağmen sadece küresel gibi DEĞİLDİR.
6502
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.