Statik anahtar kelime ve C ++ 'da çeşitli kullanımları


196

Anahtar kelime staticçok kafa karıştırıcı bulmak C ++ çeşitli anlamları olan biridir ve asla gerçekten nasıl çalışması gerekiyordu hakkında fikrimi bükmek.

Anladığım kadarıyla staticdepolama süresi var, bu da küresel bir durumda programın ömrü boyunca sürdüğü anlamına geliyor, ancak yerelden bahsederken, varsayılan olarak sıfırlandığı anlamına geliyor.

C ++ Standardı, anahtar kelimeye sahip sınıf veri üyeleri için bunu söylüyor static:

3.7.1 Statik saklama süresi [basic.stc.static]

3 static anahtar sözcüğü, statik depolama süresine sahip yerel bir değişkeni bildirmek için kullanılabilir.

4 Sınıf tanımındaki sınıf veri üyesine uygulanan statik anahtar sözcüğü, veri üyesine statik depolama süresi verir.

Yerel değişkenle ne anlama geliyor ? Bu bir işlev yerel değişkeni mi? Ayrıca, yerel bir işlevi staticyalnızca bir kez başlatıldığı için bildirdiğinizde, bu işleve ilk kez girdiğinde de vardır.

Aynı zamanda sadece sınıf üyeleri ile ilgili depolama süresinden bahsediyor, ya örneğe özgü olmama durumu hakkında, bu aynı zamanda statichayır özelliği midir? Yoksa depolama süresi mi?

Peki ya dava statickapsamı ve dosya kapsamı? Tüm global değişkenlerin varsayılan olarak statik depolama süresine sahip olduğu düşünülüyor mu? Aşağıdakiler (bölüm 3.7.1'den) bunu gösteriyor gibi görünüyor:

1 Dinamik depolama süresi olmayan, iş parçacığı depolama süresi olmayan ve yerel olmayan tüm değişkenlerin statik depolama süresi vardır. Bu kuruluşların depolanması, program süresince devam edecektir (3.6.2, 3.6.3)

staticBir değişkenin bağlantısıyla nasıl bir ilişkisi vardır?

Bu staticanahtar kelimenin tamamı düpedüz kafa karıştırıcıdır, birisi İngilizce'nin farklı kullanımlarını açıklığa kavuşturabilir ve ayrıca bir sınıf üyesini ne zaman başlatacağımı söyleyebilir staticmi?


Yanıtlar:


147

Değişkenler:

statictanımlandığı çeviri biriminin "kullanım ömrü" için değişkenler vardır ve:

  • Bir ad alanı kapsamı içindeyse (örn. İşlevlerin ve sınıfların dışında), başka bir çeviri biriminden erişilemez. Bu, "dahili bağlantı" veya "statik depolama süresi" olarak bilinir. (Bunu başlıklar dışında yapmayın constexpr. Başka bir şey ve her çeviri biriminde ayrı bir değişkenle sonuçlanırsınız, bu da kafa karıştırıcıdır)
  • Bir işlevdeki değişkense , diğer yerel değişkenler gibi işlevin dışından erişilemez. (bahsettikleri yerel budur)
  • sınıf üyelerinin sınırlı bir kapsamı yoktur static, ancak sınıftan ve bir örnek (örneğin std::string::npos) üzerinden adreslenebilir . [Not: şunları yapabilirsiniz beyan bir sınıfta statik üyeleri, ancak genellikle hareketsiz olmalıdır tanımlanmış bir çeviri birimi (cpp dosyası), ve bu şekilde, sınıf başına sadece bir tane var]

kod olarak konumlar:

static std::string namespaceScope = "Hello";
void foo() {
    static std::string functionScope= "World";
}
struct A {
   static std::string classScope = "!";
};

Bir çeviri birimindeki herhangi bir işlev yürütülmeden önce (muhtemelen mainyürütme başladıktan sonra ), o çeviri birimindeki statik depolama süresine (ad alanı kapsamı) sahip değişkenler "sabit olarak başlatılır" ( constexprmümkünse veya aksi halde sıfır) olur ve ardından yerliler düzgün "dinamik başlatıldı" olan sırayla onlar çeviri birimi tanımlanır gibi şeyler için (std::string="HI"; bunun için değil constexpr). Son olarak, işlev-yerel statikler yürütme bildirildikleri satıra ilk ulaştığında başlatılır. Tüm staticdeğişkenler ters başlatma sırasına göre yok edildi.

Tüm bu hakkı elde etmenin en kolay yolu, constexprişlev statik yerel ayarlarına başlatılmamış tüm statik değişkenleri yapmaktır ; bu, ne olursa olsun kullanmaya çalıştığınızda tüm statik / küresel değerlerinizin doğru şekilde başlatılmasını sağlar, böylece statik başlatmayı önler sipariş fiyasko .

T& get_global() {
    static T global = initial_value();
    return global;
}

Dikkatli olun, çünkü spec, ad alanı kapsamı değişkenlerinin varsayılan olarak "statik depolama süresi" olduğunu söylediğinde, "çeviri biriminin ömrü" biti anlamına gelir, ancak bu değil o dosyasının dışını erişilemez anlamına gelir.

Fonksiyonlar

Çok daha basit, static genellikle sınıf üyesi işlevi olarak kullanılır ve çok nadiren bağımsız bir işlev için kullanılır.

Statik üye işlevi, normal bir üye işlevinden, sınıf örneği olmadan çağrılabilmesi bakımından farklıdır ve hiçbir örneği olmadığından, sınıfın statik olmayan üyelerine erişemez. Statik değişkenler, kesinlikle hiçbir örnek üyeye gönderme yapmayan bir sınıf için veya staticüye değişkenleri yönetmek için bir işleve sahip olmak istediğinizde yararlıdır .

struct A {
    A() {++A_count;}
    A(const A&) {++A_count;}
    A(A&&) {++A_count;}
    ~A() {--A_count;}

    static int get_count() {return A_count;}
private:
    static int A_count;
}

int main() {
    A var;

    int c0 = var.get_count(); //some compilers give a warning, but it's ok.
    int c1 = A::get_count(); //normal way
}

Bir staticserbest fonksiyonlu fonksiyonu, herhangi bir başka geçiş birimi ile ifade edilmez ve bu nedenle bağlayıcı tamamen göz ardı anlamına gelir. Bunun az sayıda amacı vardır:

  • İşlevin hiçbir zaman başka bir dosyadan kullanılmadığını garanti etmek için bir cpp dosyasında kullanılabilir.
  • Bir başlığa konabilir ve her dosyanın fonksiyonun kendi kopyası olacaktır. Yararlı değil, çünkü inline hemen hemen aynı şeyi yapıyor.
  • İşi azaltarak bağlantı süresini kısaltır
  • Her çeviri birimine aynı ada sahip bir işlev koyabilir ve hepsi farklı şeyler yapabilir. Örneğin, static void log(const char*) {}her cpp dosyasına bir koyabilirsiniz ve her biri farklı bir şekilde günlüğe kaydedebilir.

1
Sınıf üyeleri ne olacak? Üçüncü bir dava değil mi?
Étienne

4
@Etienne - statik sınıf veri üyeleri, diğer çeviri birimlerinden erişebilmeniz dışında statik genel değişkenlerle aynıdır ve herhangi bir erişim (üye işlevleri hariç) classname::kapsamı belirtmelidir . Statik sınıf üyesi işlevleri, küresel işlevler gibidir ancak sınıfa dahil edilir veya normal üyeler gibi ancak thisbu seçenek yoktur (bu bir seçim değildir - bu ikisi eşdeğer olmalıdır).
Steve314

1
@LuchianGrigore: Ne demek istediğini görürsem, hangi ifadeyi kullanacağından emin değilim.
Mooing Duck

1
@ Steve314: Ne demek istediğini anlıyorum, ama statik olarak çok aşırı yüklü bir terimle uğraşırken , hepimiz biraz daha dikkatli olsaydık. Özellikle tüm global (gerçekten ad alanı seviyesi) değişkenler statik süreye sahiptir, bu nedenle statik global değişkenlere statik ekleme iç bağlantınamespace A { static int x; } anlamına gelir ve statik sınıf veri üyelerinin davranışlarından çok farklı olarak anlaşılabilir .
David Rodríguez - dribeas

1
"Bir ad alanı kapsamındaysa, başka bir çeviri biriminden erişilemez ..." Bir ad alanı kapsamındaysa ne demek istiyorsun? Her zaman böyle değil, bir örnek ve karşı bir örnek verebilir misiniz?
AturSams

66

Statik depolama süresi, değişkenin programın ömrü boyunca bellekte aynı yerde bulunduğu anlamına gelir.

Bağlantı buna diktir.

Bence bu yapabileceğiniz en önemli ayrım. Bunu ve geri kalanını anlamanın yanı sıra hatırlamanın da kolay olması gerekir (@Tony'e doğrudan değinmemekle birlikte, gelecekte bunu okuyabilen).

Anahtar kelime staticdahili bağlantıyı ve statik depolamayı belirtmek için kullanılabilir , ancak özünde bunlar farklıdır.

Yerel değişkenle ne anlama geliyor? Bu bir işlev yerel değişkeni mi?

Evet. Değişkenin ne zaman başlatıldığına bakılmaksızın (işleve ilk çağrıda ve yürütme yolu bildirim noktasına ulaştığında), programın ömrü boyunca bellekte aynı yerde kalır. Bu durumda, staticstatik depolama sağlar.

Şimdi statik ve dosya kapsamı olan durum ne olacak? Tüm global değişkenlerin varsayılan olarak statik depolama süresine sahip olduğu düşünülüyor mu?

Evet, tüm globaller tanım gereği statik depolama süresine sahiptir (şimdi bunun ne anlama geldiğini temizledik). Ancak ad alanı kapsamındaki değişkenler ile bildirilmez static, çünkü bu onlara iç bağlantı sağlar, bu nedenle çeviri birimi başına bir değişken olur.

Statik bir değişkenin bağlantısıyla nasıl ilişkilidir?

Ad alanı kapsamındaki değişkenlere iç bağlantı sağlar. Üyelere ve yerel değişkenlere statik depolama süresi verir.

Tüm bunları genişletelim:

//

static int x; //internal linkage
              //non-static storage - each translation unit will have its own copy of x
              //NOT A TRUE GLOBAL!

int y;        //static storage duration (can be used with extern)
              //actual global
              //external linkage
struct X
{
   static int x;     //static storage duration - shared between class instances 
};

void foo()
{
   static int x;     //static storage duration - shared between calls
}

Bu statik anahtar kelimenin tamamı düpedüz kafa karıştırıcı

Kesinlikle, eğer aşina değilseniz. :) Dile yeni anahtar kelimeler eklemekten kaçınmaya çalışan komite, bunu, IMO'yu bu amaçla yeniden kullandı - karışıklık. Farklı şeyleri ifade etmek için kullanılır (söyleyebilir miyim, muhtemelen karşıt şeyler).


1
Bunu düzleştireyim - static int xad alanı kapsamında söylediğimde, bunun statik olmayan depolama sağladığını mı söylüyorsunuz ?
Michael Hagar

31

Soruyu açıklığa kavuşturmak için, 'statik' anahtar kelimenin kullanımını üç farklı biçimde kategorize etmek istiyorum:

(A). değişkenler

(B). fonksiyonlar

(C). üye değişkenler / sınıf fonksiyonları

alt başlıkların her biri için açıklama aşağıdaki gibidir:

(A) Değişkenler için 'statik' anahtar kelime

Bu biraz zor olabilir, ancak doğru bir şekilde açıklanır ve anlaşılırsa, oldukça basittir.

Bunu açıklamak için öncelikle değişkenlerin kapsamı, süresi ve bağlantısı hakkında bilgi vermek gerçekten yararlıdır.

1. Kapsam : Dosyanın neresinde erişilebilir olduğuna karar verir. İki tip olabilir: (i) Yerel veya Blok Kapsamı . (ii) Küresel Kapsam

2. Süre : Bir değişkenin ne zaman oluşturulacağını ve yok edileceğini belirler. Yine iki tiptir: (i) Otomatik Saklama Süresi (Yerel veya Blok kapsamı olan değişkenler için). (ii) Statik Depolama Süresi (Genel Kapsamı olan değişkenler veya statik belirleyicili yerel değişkenler (bir işlevde veya bir kod bloğunda) için ).

3. Bağlantı : Bir değişkenin başka bir dosyadan erişilip erişilemeyeceğini (veya bağlanabileceğini) belirler. Yine (ve neyse ki) iki tiptir: (i) Dahili Bağlantı (Blok Kapsamı ve Global Kapsam / Dosya Kapsamı / Global Ad Alanı kapsamı olan değişkenler için ) (ii) Harici Bağlantı (sadece Global Kapsam / Dosya Kapsamı / Global Ad Alanı Kapsamı)

Düz küresel ve yerel değişkenleri daha iyi anlamak için aşağıdaki örneğe bakalım (statik depolama süresine sahip yerel değişkenler yok):

//main file
#include <iostream>

int global_var1; //has global scope
const global_var2(1.618); //has global scope

int main()
{
//these variables are local to the block main.
//they have automatic duration, i.e, they are created when the main() is 
//  executed and destroyed, when main goes out of scope
 int local_var1(23);
 const double local_var2(3.14);

 {
/* this is yet another block, all variables declared within this block are 
 have local scope limited within this block. */
// all variables declared within this block too have automatic duration, i.e, 
/*they are created at the point of definition within this block,
 and destroyed as soon as this block ends */
   char block_char1;
   int local_var1(32) //NOTE: this has been re-declared within the block, 
//it shadows the local_var1 declared outside

 std::cout << local_var1 <<"\n"; //prints 32

  }//end of block
  //local_var1 declared inside goes out of scope

 std::cout << local_var1 << "\n"; //prints 23

 global_var1 = 29; //global_var1 has been declared outside main (global scope)
 std::cout << global_var1 << "\n"; //prints 29
 std::cout << global_var2 << "\n"; //prints 1.618

 return 0;
}  //local_var1, local_var2 go out of scope as main ends
//global_var1, global_var2 go out of scope as the program terminates 
//(in this case program ends with end of main, so both local and global
//variable go out of scope together

Şimdi Bağlantı kavramı geliyor. Bir dosyada tanımlanan bir global değişkenin başka bir dosyada kullanılması amaçlandığında, değişkenin bağlantısı önemli bir rol oynar.

Global değişkenlerin bağlantısı şu anahtar kelimelerle belirtilir: (i) statik ve (ii) harici

(Şimdi açıklamayı aldınız)

statik anahtar kelime yerel ve global kapsamdaki değişkenlere uygulanabilir ve her iki durumda da farklı şeyler ifade eder. Önce küresel kapsamdaki değişkenlerde 'statik' anahtar kelime kullanımını açıklayacağım (burada 'extern' anahtar kelimesinin kullanımını da açıklığa kavuşturacağım) ve daha sonra yerel kapsamı olanlar için.

1. Küresel kapsamdaki değişkenler için Statik Anahtar Kelime

Global değişkenler statik süreye sahiptir, yani kullanıldıkları belirli bir kod bloğu (örneğin main ()) sona erdiğinde kapsam dışı kalmazlar. Bağlantıya bağlı olarak, bunlara yalnızca bildirildikleri dosya içinde (statik global değişken için) veya bildirildikleri dosyanın dışında bile (harici tip global değişkenler) erişilebilir.

Extern belirleyicisine sahip bir global değişken söz konusuysa ve bu değişkene, başlatıldığı dosyanın dışında erişiliyorsa, tıpkı bir işlevin iletilmesi gerektiği gibi, kullanıldığı dosyada ileriye doğru bildirilmelidir tanımı, kullanıldığı yerden farklı bir dosyadaysa bildirilir.

Buna karşılık, global değişken statik anahtar kelimeye sahipse, dışında bildirildiği bir dosyada kullanılamaz.

(açıklama için aşağıdaki örneğe bakın)

Örneğin:

//main2.cpp
 static int global_var3 = 23;  /*static global variable, cannot be                            
                                accessed in anyother file */
 extern double global_var4 = 71; /*can be accessed outside this file                  linked to main2.cpp */
 int main() { return 0; }

main3.cpp

//main3.cpp
#include <iostream>

int main()
{
   extern int gloabl_var4; /*this variable refers to the gloabal_var4
                            defined in the main2.cpp file */
  std::cout << global_var4 << "\n"; //prints 71;

  return 0;
}

şimdi c ++ 'daki herhangi bir değişken bir const veya const olmayan olabilir ve her' const-ness 'için, hiçbiri belirtilmemişse, iki varsayılan c ++ bağlantısı durumu elde ederiz:

(i) Genel bir değişken sabit değilse, bağlantı varsayılan olarak extern'dir , yani sabit olmayan genel değişken, extern anahtar sözcüğü kullanılarak ileri bir bildirimle başka bir .cpp dosyasında erişilebilir (başka bir deyişle, const global olmayan) değişkenler dış bağlantıya sahiptir (statik süre ile). Ayrıca, extern anahtar sözcüğünün tanımlandığı orijinal dosyada kullanılması gereksizdir. Bu durumda , sabit olmayan bir genel değişkeni harici dosyaya erişilemez hale getirmek için, değişken türünden önce 'statik' belirtecini kullanın .

(ii) Genel değişken sabitse, bağlantı varsayılan olarak statiktir , yani sabit genel değişken tanımlandığı yer dışında bir dosyaya erişilemez (başka bir deyişle, sabit genel değişkenler dahili bağlantıya sahiptir (statik süre ile) elbette)). Ayrıca, sabit bir global değişkenin başka bir dosyada erişilmesini önlemek için statik anahtar kelimenin kullanılması gereksizdir. Burada, sabit bir global değişkenin harici bir bağlantıya sahip olması için, değişken türünden önce 'extern' belirtecini kullanın

Çeşitli bağlantılara sahip global kapsam değişkenleri için bir özet

//globalVariables1.cpp 

// defining uninitialized vairbles
int globalVar1; //  uninitialized global variable with external linkage 
static int globalVar2; // uninitialized global variable with internal linkage
const int globalVar3; // error, since const variables must be initialized upon declaration
const int globalVar4 = 23; //correct, but with static linkage (cannot be accessed outside the file where it has been declared*/
extern const double globalVar5 = 1.57; //this const variable ca be accessed outside the file where it has been declared

Daha sonra, yukarıdaki küresel değişkenlerin farklı bir dosyaya erişildiğinde nasıl davrandığını araştırıyoruz.

//using_globalVariables1.cpp (eg for the usage of global variables above)

// Forward declaration via extern keyword:
 extern int globalVar1; // correct since globalVar1 is not a const or static
 extern int globalVar2; //incorrect since globalVar2 has internal linkage
 extern const int globalVar4; /* incorrect since globalVar4 has no extern 
                         specifier, limited to internal linkage by
                         default (static specifier for const variables) */
 extern const double globalVar5; /*correct since in the previous file, it 
                           has extern specifier, no need to initialize the
                       const variable here, since it has already been
                       legitimately defined perviously */

2. Yerel Kapsamlı değişkenler için Statik Anahtar Kelime

Yerel kapsamdaki değişkenler için statik anahtar kelimeyle ilgili güncellemeler (Ağustos 2019)

Bu ayrıca iki kategoriye ayrılabilir:

(i) bir işlev bloğundaki değişkenler için statik anahtar kelime ve (ii) adsız bir yerel blok içindeki değişkenler için statik anahtar kelime.

(i) bir fonksiyon bloğundaki değişkenler için statik anahtar kelime.

Daha önce, yerel kapsamdaki değişkenlerin otomatik süreye sahip olduğunu, yani blok girildiğinde (normal bir blok olsun, bir fonksiyon bloğu olsun) var olduklarını ve blok bittiğinde, uzun öykü kısa, değişkenlerde var olduklarını belirttim. yerel kapsamda otomatik süre vardır ve otomatik süre değişkenleri (ve nesneler) hiçbir bağlantı yoktur yani kod bloğu dışında görünmez.

Eğer statik belirleyici bir işlev bloğu dahilinde yerel bir değişkene uygulanır, statik otomatik değişkenin süresini değiştirir ve yaşam süresi, sabit bellek konuma sahiptir araçları programının tamamı süresi ve değeri sadece başlatıldı cpp referansında belirtildiği gibi program başlatılmadan önce (başlatma, atama ile karıştırılmamalıdır)

bir örneğe bakalım.

//localVarDemo1.cpp    
 int localNextID()
{
  int tempID = 1;  //tempID created here
  return tempID++; //copy of tempID returned and tempID incremented to 2
} //tempID destroyed here, hence value of tempID lost

int newNextID()
{
  static int newID = 0;//newID has static duration, with internal linkage
  return newID++; //copy of newID returned and newID incremented by 1
}  //newID doesn't get destroyed here :-)


int main()
{
  int employeeID1 = localNextID();  //employeeID1 = 1
  int employeeID2 = localNextID();  // employeeID2 = 1 again (not desired)
  int employeeID3 = newNextID(); //employeeID3 = 0;
  int employeeID4 = newNextID(); //employeeID4 = 1;
  int employeeID5 = newNextID(); //employeeID5 = 2;
  return 0;
}

Statik yerel değişkenler ve statik küresel değişkenler için yukarıdaki kritere bakıldığında, aralarındaki farkın ne olabileceğini sormak cazip gelebilir. Global değişkenler kodun herhangi bir noktasında erişilebilir olsa da ( const -ness ve extern -ness'e bağlı olarak farklı çeviri biriminde olduğu gibi ), bir fonksiyon bloğu içinde tanımlanan statik bir değişkene doğrudan erişilemez. Değişkenin işlev değeri veya başvurusu ile döndürülmesi gerekir. Bunu bir örnekle gösterelim:

//localVarDemo2.cpp 

//static storage duration with global scope 
//note this variable can be accessed from outside the file
//in a different compilation unit by using `extern` specifier
//which might not be desirable for certain use case.
static int globalId = 0;

int newNextID()
{
  static int newID = 0;//newID has static duration, with internal linkage
  return newID++; //copy of newID returned and newID incremented by 1
}  //newID doesn't get destroyed here


int main()
{
    //since globalId is accessible we use it directly
  const int globalEmployee1Id = globalId++; //globalEmployeeId1 = 0;
  const int globalEmployee2Id = globalId++; //globalEmployeeId1 = 1;

  //const int employeeID1 = newID++; //this will lead to compilation error since newID++ is not accessible direcly. 
  int employeeID2 = newNextID(); //employeeID3 = 0;
  int employeeID2 = newNextID(); //employeeID3 = 1;

  return 0;
}

Statik global ve statik lokal değişken seçimi hakkında daha fazla açıklama bu yığın akışı iş parçacığında bulunabilir

(ii) adlandırılmamış bir yerel blok içindeki değişkenler için statik anahtar kelime.

yerel blok kapsam dışına çıktığında, yerel bir blok içindeki statik değişkenlere (fonksiyon bloğu değil) blok dışında erişilemez. Bu kurala dikkat edilmez.

    //localVarDemo3.cpp 
    int main()
    {

      {
          const static int static_local_scoped_variable {99};
      }//static_local_scoped_variable goes out of scope

      //the line below causes compilation error
      //do_something is an arbitrary function
      do_something(static_local_scoped_variable);
      return 0;
    }

C ++ 11 constexpr, bir ifadenin derleme zamanında değerlendirilmesini garanti eden ve derleyicinin kodu optimize etmesine izin veren anahtar kelimeyi tanıttı . Şimdi, bir kapsam içindeki statik sabit değişkenin değeri derleme zamanında biliniyorsa, kod, şuna benzer bir şekilde optimize edilir constexpr. İşte küçük bir örnek

Ben arasındaki farkı bakmak için de okuyucuları tavsiye constexprve static constdeğişkenler için bu stackoverflow iş parçacığı . bu, değişkenlere uygulanan statik anahtar kelimeye ilişkin açıklamamın sonucudur.

B. işlevler için kullanılan 'statik' anahtar kelime

işlevler açısından, statik anahtar kelimenin açık bir anlamı vardır. Burada, fonksiyonun bağlantısına atıfta bulunur. Normalde, bir cpp dosyası içinde bildirilen tüm fonksiyonların varsayılan olarak harici bağlantısı vardır, yani bir dosyada tanımlanan bir fonksiyon, ileri bildirimle başka bir cpp dosyasında kullanılabilir.

işlev bildirimi bağlantısını dahili ile sınırlamadan önce statik bir anahtar kelime kullanmak , yani statik işlev tanımının dışındaki bir dosyada kullanılamaz.

C. Staitc Sınıfların üye değişkenleri ve işlevleri için kullanılan anahtar kelime

1. sınıfların üye değişkenleri için 'statik' anahtar kelime

Doğrudan burada bir örnekle başlıyorum

#include <iostream>

class DesignNumber
{
  private:

      static int m_designNum;  //design number
      int m_iteration;     // number of iterations performed for the design

  public:
    DesignNumber() {     }  //default constructor

   int  getItrNum() //get the iteration number of design
   {
      m_iteration = m_designNum++;
      return m_iteration;
   }
     static int m_anyNumber;  //public static variable
};
int DesignNumber::m_designNum = 0; // starting with design id = 0
                     // note : no need of static keyword here
                     //causes compiler error if static keyword used
int DesignNumber::m_anyNumber = 99; /* initialization of inclass public 
                                    static member  */
enter code here

int main()
{
   DesignNumber firstDesign, secondDesign, thirdDesign;
   std::cout << firstDesign.getItrNum() << "\n";  //prints 0
   std::cout << secondDesign.getItrNum() << "\n"; //prints 1
   std::cout << thirdDesign.getItrNum() << "\n";  //prints 2

   std::cout << DesignNumber::m_anyNumber++ << "\n";  /* no object
                                        associated with m_anyNumber */
   std::cout << DesignNumber::m_anyNumber++ << "\n"; //prints 100
   std::cout << DesignNumber::m_anyNumber++ << "\n"; //prints 101

   return 0;
}

Bu örnekte, m_designNum statik değişkeni değerini korur ve bu tek özel üye değişken (statik olduğu için) DesignNumber nesne türünün tüm değişkenleri s / b ile paylaşılır

Ayrıca, diğer üye değişkenler gibi, bir sınıfın statik üye değişkenleri herhangi bir sınıf nesnesiyle ilişkilendirilmez; bu, ana işlevde herhangi birNumber öğesinin yazdırılmasıyla gösterilir

const ve const olmayan statik üye değişkenler

(i) sabit olmayan sınıf statik üye değişkenleri Önceki örnekte, statik üyeler (hem genel hem de özel) sabit değildir. ISO standardı, sınıfta sabit olmayan statik üyelerin başlatılmasını yasaklar. Dolayısıyla, önceki örnekte olduğu gibi, sınıf tanımından sonra statik anahtar kelimenin atlanması gereken uyarı ile birlikte başlatılmaları gerekir.

(ii) sınıfının const-statik üye değişkenler bu pürüzsüz olup, diğer sabit eleman değişken başlatma esası ile gider, bir sınıf, yani const statik üye değişkeni olabilir beyan noktasında başlatıldı ve sonunda başlatıldı edilebilir sınıf tanımlamasından sonra başlatılırken const anahtar sözcüğünün statik üyeye eklenmesi gerektiği konusunda bir uyarı.

Ancak, bildiri noktasında const statik üye değişkenleri başlatmanızı tavsiye ederim. Bu standart C ++ kuralına uygundur ve kodun daha temiz görünmesini sağlar

bir sınıftaki statik üye değişkenleri hakkında daha fazla örnek için learncpp.com adresinden aşağıdaki bağlantıya bakın http://www.learncpp.com/cpp-tutorial/811-static-member-variables/

2. sınıfların üye işlevi için 'statik' anahtar kelime

Sınıfların üye değişkenleri gibi statik olabilir, sınıfların üye işlevleri de olabilir. Sınıfların normal üye işlevleri her zaman sınıf türündeki bir nesne ile ilişkilendirilir. Aksine, bir sınıfın statik üye işlevleri sınıfın herhangi bir nesnesiyle ilişkilendirilmez, yani * bu işaretçiye sahip değildir.

İkincisi, sınıfın statik üye işlevlerinde * hiçbir bu işaretçi olmadığından, bunlar ana işlevdeki (ClassName :: functionName ();) sınıf adı ve kapsam çözümleme işleci kullanılarak çağrılabilir.

Bir sınıfın üçüncü olarak statik üye işlevleri, bir sınıfın yalnızca statik üye değişkenlerine erişebilir, çünkü bir sınıfın statik olmayan üye değişkenleri bir sınıf nesnesine ait olmalıdır.

bir sınıftaki statik üye işlevleri hakkında daha fazla örnek için learncpp.com adresinden aşağıdaki bağlantıya bakın

http://www.learncpp.com/cpp-tutorial/812-static-member-functions/


1
1) c ++ 17'den önce sadece integral statik sabit üye struct Foo{static const std::string name = "cpp";};değişkenleri sınıf içinde başlatılabilir, örneğin hata, namesınıf dışında tanımlanmalıdır; Satır içi değişkenler c ++ 17'de struct Foo{static inline const std::string name = "cpp";};
izinsiz girildiğinde kodlanabilir

"M_anyVariable", "m_anyNumber" olmamalı mı? Son kod örneğinizde?
gebbissimo

Cevabın eksiksizliğini ve doğruluğunu yargılayamıyorum, ancak gerçekten kapsamlı görünüyor ve takip edilmesi kolaydı. Çok teşekkürler! Eğer geliştirmek istiyorsanız, başlangıçta kısa bir özet faydalı olabilir, çünkü oldukça uzun bir metindir ve ana noktalar "iç / dış" linkage "
gebbissimo

18

Aslında oldukça basit. Bir değişkeni bir işlev kapsamında statik olarak bildirirseniz, değeri o işleve ardışık çağrılar arasında korunur. Yani:

int myFun()
{
static int i=5;
i++;
return i;
}
int main()
{
printf("%d", myFun());
printf("%d", myFun());
printf("%d", myFun());
}

Bunun 678yerine gösterilecektir 666, çünkü artan değeri hatırlar.

Statik üyelere gelince, sınıf örnekleri boyunca değerlerini korurlar. Yani aşağıdaki kod:

struct A
{
static int a;
};
int main()
{
A first;
A second;
first.a = 3;
second.a = 4;
printf("%d", first.a);
}

4'ü yazdırır, çünkü first.a ve second.a aslında aynı değişkendir. Başlatma için bu soruya bakın .


Bu, ad alanı kapsam değişkenlerini ele almaz.
Michael Hagar

10

staticDosya kapsamında bir değişken bildirdiğinizde , bu değişken yalnızca o dosyada kullanılabilir (teknik olarak * çeviri birimi, ancak bunu çok fazla karmaşık hale getirmeyelim). Örneğin:

a.cpp

static int x = 7;

void printax()
{
    cout << "from a.cpp: x=" << x << endl;
}

b.cpp

static int x = 9;

void printbx()
{
    cout << "from b.cpp: x=" << x << endl;
}

main.cpp:

int main(int, char **)
{
    printax(); // Will print 7
    printbx(); // Will print 9

    return 0;
}

Bir için yerel bir değişken, staticaracı değişken sıfır başlatılmış olacağı ve çağrılar arasında değerini korumak:

unsigned int powersoftwo()
{
    static unsigned lastpow;

    if(lastpow == 0)
        lastpow = 1;
    else
        lastpow *= 2;

    return lastpow;
}

int main(int, char **)
{
    for(int i = 0; i != 10; i++)
        cout << "2^" << i << " = " << powersoftwo() << endl;
}

İçin sınıf değişkenleri, bu sınıfın tüm üyeleri arasında paylaşılır o değişkenin sadece tek bir örneği olduğu anlamına gelir. İzinlere bağlı olarak, değişkene tam adı kullanılarak sınıfın dışından erişilebilir.

class Test
{
private:
    static char *xxx;

public:
    static int yyy;

public:
    Test()
    {        
        cout << this << "The static class variable xxx is at address "
             << static_cast<void *>(xxx) << endl;
        cout << this << "The static class variable yyy is at address "
             << static_cast<void *>(&y) << endl;
    }
};

// Necessary for static class variables.
char *Test::xxx = "I'm Triple X!";
int Test::yyy = 0;

int main(int, char **)
{
    Test t1;
    Test t2;

    Test::yyy = 666;

    Test t3;
};

Sınıf dışı bir işlevi işaretlemek static, işlevin yalnızca bu dosyadan erişilebilir olmasını ve diğer dosyalardan erişilememesini sağlar.

a.cpp

static void printfilename()
{ // this is the printfilename from a.cpp - 
  // it can't be accessed from any other file
    cout << "this is a.cpp" << endl;
}

b.cpp

static void printfilename()
{ // this is the printfilename from b.cpp - 
  // it can't be accessed from any other file
    cout << "this is b.cpp" << endl;
}

Sınıf üyesi işlevleri için, bunları işaretlemek static, işlevin belirli bir nesne örneğinde çağrılması gerekmediği anlamına gelir (yani bir thisişaretçisi yoktur).

class Test
{
private:
    static int count;

public:
    static int GetTestCount()
    {
        return count;
    };

    Test()
    {
        cout << this << "Created an instance of Test" << endl;
        count++;
    }

    ~Test()
    {
        cout << this << "Destroyed an instance of Test" << endl;
        count--;
    }
};

int Test::count = 0;

int main(int, char **)
{
    Test *arr[10] = { NULL };

    for(int i = 0; i != 10; i++)
        arr[i] = new Test();

    cout << "There are " << Test::GetTestCount() << " instances of the Test class!" << endl;

    // now, delete them all except the first and last!
    for(int i = 1; i != 9; i++)
        delete arr[i];        

    cout << "There are " << Test::GetTestCount() << " instances of the Test class!" << endl;

    delete arr[0];

    cout << "There are " << Test::GetTestCount() << " instances of the Test class!" << endl;

    delete arr[9];

    cout << "There are " << Test::GetTestCount() << " instances of the Test class!" << endl;

    return 0;
}

8

Statik değişkenler, her sınıfın kendi değişkenine sahip olması yerine, sınıfın her örneği arasında paylaşılır.

class MyClass
{
    public:
    int myVar; 
    static int myStaticVar;
};

//Static member variables must be initialized. Unless you're using C++11, or it's an integer type,
//they have to be defined and initialized outside of the class like this:
MyClass::myStaticVar = 0;

MyClass classA;
MyClass classB;

Her 'MyClass' örneğinin kendi 'myVar' değeri vardır, ancak aynı 'myStaticVar'ı paylaşır. Aslında, 'myStaticVar' öğesine erişmek için bir MyClass örneğine bile ihtiyacınız yoktur ve buna sınıfın dışında şu şekilde erişebilirsiniz:

MyClass::myStaticVar //Assuming it's publicly accessible.

Bir işlev içinde yerel değişken olarak (ve sınıf üyesi değişkeni olarak değil) kullanıldığında, statik anahtar kelime farklı bir şey yapar. Global kapsam vermeden kalıcı bir değişken oluşturmanıza olanak tanır.

int myFunc()
{
   int myVar = 0; //Each time the code reaches here, a new variable called 'myVar' is initialized.
   myVar++;

   //Given the above code, this will *always* print '1'.
   std::cout << myVar << std::endl;

   //The first time the code reaches here, 'myStaticVar' is initialized. But ONLY the first time.
   static int myStaticVar = 0;

   //Each time the code reaches here, myStaticVar is incremented.
   myStaticVar++;

   //This will print a continuously incrementing number,
   //each time the function is called. '1', '2', '3', etc...
   std::cout << myStaticVar << std::endl;
}

Kalıcılık açısından küresel bir değişkendir ... ancak kapsam / erişilebilirlik konusunda küresel olmadan.

Ayrıca statik üye işlevleriniz de olabilir. Statik işlevler temelde üye olmayan işlevlerdir, ancak sınıf adının ad alanının içinde ve sınıf üyelerine özel erişime sahiptir.

class MyClass
{
    public:
    int Func()
    {
        //...do something...
    }

    static int StaticFunc()
    {
        //...do something...
    }
};

int main()
{
   MyClass myClassA;
   myClassA.Func(); //Calls 'Func'.
   myClassA.StaticFunc(); //Calls 'StaticFunc'.

   MyClass::StaticFunc(); //Calls 'StaticFunc'.
   MyClass::Func(); //Error: You can't call a non-static member-function without a class instance!

   return 0;
}

Bir üye işlevini çağırdığınızda, 'this' adında gizli bir parametre vardır; bu, işlevi çağıran sınıf örneğinin bir göstergesidir. Statik üye işlevleri bu gizli parametreye sahip değildir ... bir sınıf örneği olmadan çağrılabilirler, ancak bir sınıfın statik olmayan üye değişkenlerine erişemezler, çünkü üzerinde çalışacak bir 'bu' işaretçisi yoktur. Herhangi bir sınıf örneğinde çağrılmazlar.


1
"Herkese açık olduğunu varsayarsak." - değil.
Luchian Grigore

2
myStaticVarayrıca tanımlanması gerekir. staticAnahtar kelimenin anlam bilgisi hakkında bir soruya cevap verirken düşünmemeniz önemli.
Praetorian

@Praetorian: Teşekkürler, düzeltildi.
Jamin Grey

1
@JaminGrey "statik bağımsız" ile statik üye olmayan işlevleri kastediyordum ve sadece geçerli CPP dosyasında bazı yeni işlevlere ihtiyaç duyduğumda yazıyorum ve bağlayıcı ek bir sembol işlemek istemiyorum.
VR

1
@VR Odd! Hiçbir zaman işlevsellik olduğunu bilmiyordum . Bilgilerimi genişlettiğiniz için teşekkürler!
Jamin Grey

1

Ben bir C programcısı değilim, bu yüzden düzgün bir C programında statik kullanımları hakkında bilgi veremem, ancak Nesne Yönelimli programlama söz konusu olduğunda, statik temelde bir değişken veya bir işlev veya bir sınıfın aynı olduğunu bildirir programın ömrü boyunca. Örneğin ele alalım.

class A
{
public:
    A();
    ~A();
    void somePublicMethod();
private:
    void somePrivateMethod();
};

Bu sınıfı Main'inizde başlattığınızda böyle bir şey yaparsınız.

int main()
{
   A a1;
   //do something on a1
   A a2;
   //do something on a2
}

Bu iki sınıf örneği birbirinden tamamen farklıdır ve birbirlerinden bağımsız olarak çalışırlar. Ama eğer A sınıfını böyle yaratacak olsaydın.

class A
{
public:
    A();
    ~A();
    void somePublicMethod();
    static int x;
private:
    void somePrivateMethod();
};

Tekrar anaya dönelim.

int main()
{
   A a1;
   a1.x = 1;
   //do something on a1
   A a2;
   a2.x++;
   //do something on a2
}

Daha sonra a1 ve a2, int x'in aynı kopyasını paylaşır, böylece a1'deki x üzerindeki herhangi bir işlem, a2'deki x'in işlemlerini doğrudan etkiler. Eğer bunu yapacak olsaydım

int main()
{
   A a1;
   a1.x = 1;
   //do something on a1
   cout << a1.x << endl; //this would be 1
   A a2;
   a2.x++;
   cout << a2.x << endl; //this would be 2 
   //do something on a2
}

A sınıfının her iki örneği de statik değişkenleri ve işlevleri paylaşır. Umarım bu soruya cevap verir. Sınırlı C bilgim, bir işlevi veya değişkeni statik olarak tanımlamanın, yalnızca işlevin veya değişkenin statik olarak tanımlandığı dosyada görülebileceği anlamına geldiğini söylememe izin veriyor. C ++, hem C hem de C ++ yöntemlerinin değişkenlerinizi statik olarak bildirmesine izin verir, çünkü C ile tamamen geriye doğru uyumludur.


1

Yerel değişkenle ne anlama geliyor? Bu bir işlev yerel değişkeni mi?

Evet - Bir işlev yerel değişkeni gibi genel olmayan.

Çünkü yerel bir işlevi statik olarak yalnızca bir kez başlatıldığını bildirdiğinizde, bu işleve ilk girdiğinde de vardır.

Sağ.

Ayrıca sadece sınıf üyeleri ile ilgili depolama süresinden bahsediyor, ya örneğe özgü olmayan, aynı zamanda statik no'nun bir özelliği? Yoksa depolama süresi mi?

class R { static int a; }; // << static lives for the duration of the program

demek olduğunu, tüm örnekleri Rpayı int R::a- int R::akopyalanmış asla.

Şimdi statik ve dosya kapsamı olan durum ne olacak?

Etkili bir şekilde yapıcı / yıkıcıya sahip bir küresel - uygun şekilde başlatma, erişime kadar ertelenmez.

Statik bir değişkenin bağlantısıyla nasıl ilişkilidir?

Yerel bir işlev için harici bir işlevdir. Erişim: İşlev tarafından erişilebilir (tabii ki iade etmezseniz).

Bir sınıf için harici. Erişim: Standart erişim belirteçleri geçerlidir (genel, korumalı, özel).

static bildirildiği yere (dosya / ad alanı) bağlı olarak dahili bağlantı da belirtebilir.

Bu statik anahtar kelimenin tamamı düpedüz kafa karıştırıcı

C ++ 'da çok fazla amacı vardır.

Birisi İngilizce'nin farklı kullanımlarını açıklığa kavuşturabilir ve bana statik sınıf üyesini ne zaman başlatacağımı söyleyebilir mi?

mainYüklendiğinde ve bir kurucuya sahip olmadan önce otomatik olarak başlatılır . Bu iyi bir şey gibi gelebilir, ancak başlatma sırası büyük ölçüde kontrolünüzün ötesindedir, bu nedenle karmaşık başlatmanın sürdürülmesi çok zorlaşır ve bunu en aza indirmek istersiniz - statik olmanız gerekiyorsa, kütüphaneler arasında yerel ölçekleri çok daha iyi çalışır ve projeler. Statik depolama süresine sahip verilere gelince, bu tasarımı, özellikle değişebilir durumdaysa (genel değişkenler) en aza indirmeye çalışmalısınız. Başlatma 'süresi' de çeşitli nedenlerden dolayı değişir - yükleyici ve çekirdek, söz konusu verilere bağlı olarak bellek ayak izlerini en aza indirmek ve başlatmayı ertelemek için bazı hilelere sahiptir.


1

Statik Nesne: Statik anahtar sözcük kullanarak sınıf üyelerini statik olarak tanımlayabiliriz. Bir sınıfın bir üyesini statik olarak ilan ettiğimizde, sınıfın kaç nesnesi oluşturulmuş olursa olsun, statik üyenin yalnızca bir kopyası vardır.

Statik üye sınıfın tüm nesneleri tarafından paylaşılır. Başka bir başlatma yoksa, ilk nesne oluşturulduğunda tüm statik veriler sıfırlanır. Sınıf tanımına koyamayız, ancak sınıfın dışında, hangi sınıfa ait olduğunu tanımlamak için scope çözünürlük operatörü :: kullanılarak statik değişkeni yeniden bildirerek başlatılabilir.

Statik veri üyeleri kavramını anlamak için aşağıdaki örneği deneyelim:

#include <iostream>

using namespace std;

class Box
{
   public:
      static int objectCount;
      // Constructor definition
      Box(double l=2.0, double b=2.0, double h=2.0)
      {
         cout <<"Constructor called." << endl;
         length = l;
         breadth = b;
         height = h;
         // Increase every time object is created
         objectCount++;
      }
      double Volume()
      {
         return length * breadth * height;
      }
   private:
      double length;     // Length of a box
      double breadth;    // Breadth of a box
      double height;     // Height of a box
};

// Initialize static member of class Box
int Box::objectCount = 0;

int main(void)
{
   Box Box1(3.3, 1.2, 1.5);    // Declare box1
   Box Box2(8.5, 6.0, 2.0);    // Declare box2

   // Print total number of objects.
   cout << "Total objects: " << Box::objectCount << endl;

   return 0;
}

Yukarıdaki kod derlendiğinde ve yürütüldüğünde, aşağıdaki sonucu verir:

Constructor called.
Constructor called.
Total objects: 2

Statik İşlev Üyeleri: Bir işlev üyesini statik olarak bildirerek, üyeyi sınıfın herhangi bir nesnesinden bağımsız hale getirirsiniz. Sınıfın herhangi bir nesnesi olmasa ve statik fonksiyonlara yalnızca sınıf adı ve kapsam çözümleme operatörü :: kullanılarak erişilse bile statik üye işlevi çağrılabilir.

Statik üye işlevi yalnızca statik veri üyesine, diğer statik üye işlevlerine ve sınıf dışındaki diğer işlevlere erişebilir.

Statik üye işlevlerinin bir sınıf kapsamı vardır ve sınıfın bu işaretçisine erişimleri yoktur. Sınıfın bazı nesnelerinin yaratılıp yaratılmadığını belirlemek için statik üye işlevi kullanabilirsiniz.

Statik fonksiyon üyeleri kavramını anlamak için aşağıdaki örneği deneyelim:

#include <iostream>

using namespace std;

class Box
{
   public:
      static int objectCount;
      // Constructor definition
      Box(double l=2.0, double b=2.0, double h=2.0)
      {
         cout <<"Constructor called." << endl;
         length = l;
         breadth = b;
         height = h;
         // Increase every time object is created
         objectCount++;
      }
      double Volume()
      {
         return length * breadth * height;
      }
      static int getCount()
      {
         return objectCount;
      }
   private:
      double length;     // Length of a box
      double breadth;    // Breadth of a box
      double height;     // Height of a box
};

// Initialize static member of class Box
int Box::objectCount = 0;

int main(void)
{

   // Print total number of objects before creating object.
   cout << "Inital Stage Count: " << Box::getCount() << endl;

   Box Box1(3.3, 1.2, 1.5);    // Declare box1
   Box Box2(8.5, 6.0, 2.0);    // Declare box2

   // Print total number of objects after creating object.
   cout << "Final Stage Count: " << Box::getCount() << endl;

   return 0;
}

Yukarıdaki kod derlendiğinde ve yürütüldüğünde, aşağıdaki sonucu verir:

Inital Stage Count: 0
Constructor called.
Constructor called.
Final Stage Count: 2

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.