Kata kunci statis dan berbagai kegunaannya dalam C ++


195

Kata kunci staticadalah salah satu yang memiliki beberapa makna dalam C + + yang saya temukan sangat membingungkan dan saya tidak pernah bisa membengkokkan pikiran saya tentang bagaimana sebenarnya seharusnya bekerja.

Dari apa yang saya mengerti ada staticdurasi penyimpanan, yang berarti bahwa itu berlangsung selama seumur hidup program dalam kasus global, tetapi ketika Anda berbicara tentang lokal, itu berarti nol diinisialisasi secara default.

Standar C ++ mengatakan ini untuk anggota data kelas dengan kata kunci static:

3.7.1 Durasi penyimpanan statis [basic.stc.static]

3 Kata kunci statis dapat digunakan untuk mendeklarasikan variabel lokal dengan durasi penyimpanan statis.

4 Kata kunci statis diterapkan ke anggota data kelas dalam definisi kelas memberikan durasi penyimpanan statis anggota data.

Apa artinya dengan variabel lokal ? Apakah itu variabel fungsi lokal? Karena ada juga yang ketika Anda mendeklarasikan fungsi lokal sebagai staticitu hanya diinisialisasi sekali, pertama kali memasuki fungsi ini.

Itu juga hanya berbicara tentang durasi penyimpanan berkenaan dengan anggota kelas, bagaimana dengan itu tidak spesifik misalnya, itu juga properti dari staticno? Atau apakah itu durasi penyimpanan?

Sekarang bagaimana dengan kasing staticdan ruang lingkup file? Apakah semua variabel global dianggap memiliki durasi penyimpanan statis secara default? Berikut ini (dari bagian 3.7.1) tampaknya mengindikasikan demikian:

1 Semua variabel yang tidak memiliki durasi penyimpanan dinamis, tidak memiliki durasi penyimpanan utas, dan tidak lokal memiliki durasi penyimpanan statis. Penyimpanan untuk entitas ini akan berlangsung selama durasi program (3.6.2, 3.6.3)

Bagaimana statichubungannya dengan keterkaitan suatu variabel?

Seluruh statickata kunci ini benar-benar membingungkan, dapatkah seseorang mengklarifikasi kegunaan yang berbeda untuk bahasa Inggris dan juga memberi tahu saya kapan harus menginisialisasi anggota statickelas?


Jawaban:


147

Variabel:

staticvariabel ada untuk "seumur hidup" dari unit terjemahan yang didefinisikan , dan:

  • Jika berada dalam lingkup namespace (yaitu di luar fungsi dan kelas), maka itu tidak dapat diakses dari unit terjemahan lainnya. Ini dikenal sebagai "hubungan internal" atau "durasi penyimpanan statis". (Jangan lakukan ini di header kecuali untukconstexpr . Ada lagi, dan Anda berakhir dengan variabel terpisah di setiap unit terjemahan, yang gila membingungkan)
  • Jika itu adalah variabel dalam suatu fungsi , itu tidak dapat diakses dari luar fungsi, sama seperti variabel lokal lainnya. (ini adalah lokal yang mereka sebutkan)
  • anggota kelas tidak memiliki ruang lingkup terbatas karena static, tetapi dapat diatasi dari kelas serta instance (seperti std::string::npos). [Catatan: Anda dapat mendeklarasikan anggota statis di kelas, tetapi mereka biasanya masih harus didefinisikan dalam unit terjemahan (file cpp), dan karenanya, hanya ada satu per kelas]

lokasi sebagai kode:

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

Sebelum fungsi apa pun dalam unit terjemahan dieksekusi (mungkin setelah maindimulainya eksekusi), variabel dengan durasi penyimpanan statis (ruang lingkup namespace) dalam unit terjemahan tersebut akan "diinisialisasi konstan" ( constexprjika mungkin, atau nol jika tidak), dan kemudian non- penduduk setempat "diinisialisasi secara dinamis" dengan benar sesuai urutan yang ditentukan dalam unit terjemahan (untuk hal-hal seperti std::string="HI";itu tidak constexpr). Akhirnya, statika fungsi-lokal akan diinisialisasi saat eksekusi pertama kali "mencapai" garis di mana mereka dinyatakan. Semua staticvariabel hancur dalam urutan terbalik inisialisasi.

Cara termudah untuk mendapatkan semua ini dengan benar adalah membuat semua variabel statis yang tidak constexprdiinisialisasi ke dalam fungsi lokal statis, yang memastikan semua statika / global Anda diinisialisasi dengan benar ketika Anda mencoba menggunakannya tidak peduli apa pun, sehingga mencegah inisialisasi statis memesan kegagalan .

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

Hati-hati, karena ketika spesifikasi mengatakan variabel namespace-scope memiliki "durasi penyimpanan statis" secara default, mereka berarti bit "seumur hidup unit terjemahan", tetapi itu tidak berarti itu tidak dapat diakses di luar file.

Fungsi

Secara signifikan lebih mudah, staticsering digunakan sebagai fungsi anggota kelas, dan hanya sangat jarang digunakan untuk fungsi berdiri bebas.

Fungsi anggota statis berbeda dari fungsi anggota biasa sehingga dapat dipanggil tanpa turunan kelas, dan karena tidak memiliki turunan, ia tidak dapat mengakses anggota kelas yang tidak statis. Variabel statis berguna ketika Anda ingin memiliki fungsi untuk kelas yang sama sekali tidak merujuk ke anggota contoh, atau untuk mengelola staticvariabel anggota.

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
}

Fungsi staticbebas berarti bahwa fungsi tersebut tidak akan dirujuk oleh unit terjemahan lain, dan dengan demikian penghubung dapat mengabaikannya sepenuhnya. Ini memiliki sejumlah kecil tujuan:

  • Dapat digunakan dalam file cpp untuk menjamin bahwa fungsi tersebut tidak pernah digunakan dari file lain.
  • Dapat diletakkan di header dan setiap file akan memiliki salinan fungsinya sendiri. Tidak berguna, karena inline melakukan hal yang hampir sama.
  • Mempercepat waktu tautan dengan mengurangi pekerjaan
  • Dapat menempatkan fungsi dengan nama yang sama di setiap unit terjemahan, dan mereka semua dapat melakukan hal yang berbeda. Sebagai contoh, Anda bisa meletakkan static void log(const char*) {}di setiap file cpp, dan mereka masing-masing bisa login dengan cara yang berbeda.

1
Bagaimana dengan anggota kelas? Bukankah ini kasus terpisah ketiga?
Étienne

4
@ Etienne - anggota data kelas statis sama dengan variabel global statis kecuali Anda dapat mengaksesnya dari unit terjemahan lain, dan akses apa pun (kecuali dari fungsi anggota) harus menentukan classname::cakupannya. Fungsi anggota kelas statis seperti fungsi global tetapi mencakup kelas, atau seperti anggota normal tetapi tanpa this(itu bukan pilihan - keduanya harus setara).
Steve314

1
@LuchianGrigore: selagi saya mengerti maksud Anda, saya tidak yakin apa kata yang akan digunakan.
Mooing Duck

1
@ Steve314: Saya mengerti maksud Anda, tetapi ketika berhadapan dengan istilah yang terlalu berlebihan sebagai statis , saya berharap kita semua lebih berhati-hati. Secara khusus semua variabel global (benar-benar tingkat namespace) memiliki durasi statis, sehingga menambahkan statis dalam variabel global statis dapat dipahami sebagai namespace A { static int x; }, yang berarti hubungan internal dan sangat berbeda dari perilaku anggota data kelas statis .
David Rodríguez - dribeas

1
"Jika itu dalam lingkup namespace, maka itu tidak dapat diakses dari unit terjemahan lain ..." Apa maksud Anda jika itu dalam lingkup namespace? Bukankah itu selalu demikian, dapatkah Anda memberikan contoh dan contoh balasan?
AturSams

66

Durasi penyimpanan statis berarti bahwa variabel berada di tempat yang sama dalam memori selama masa program.

Keterkaitan adalah ortogonal untuk ini.

Saya pikir ini adalah perbedaan paling penting yang dapat Anda buat. Memahami hal ini dan yang lainnya, serta mengingatnya, harus mudah (tidak menangani @Tony secara langsung, tetapi siapa pun yang mungkin membaca ini di masa mendatang).

Kata kunci staticdapat digunakan untuk menunjukkan hubungan internal dan penyimpanan statis, tetapi pada dasarnya ini berbeda.

Apa artinya dengan variabel lokal? Apakah itu variabel fungsi lokal?

Iya. Terlepas dari kapan variabel diinisialisasi (panggilan pertama ke fungsi dan ketika jalur eksekusi mencapai titik deklarasi), variabel tersebut akan berada di tempat yang sama di memori selama umur program. Dalam hal ini, staticberikan penyimpanan statis.

Sekarang bagaimana dengan kasing statis dan ruang lingkup file? Apakah semua variabel global dianggap memiliki durasi penyimpanan statis secara default?

Ya, semua global memiliki durasi penyimpanan statis menurut definisi (sekarang kami telah membersihkan apa artinya). Tetapi variabel ruang lingkup namespace tidak dideklarasikan dengan static, karena itu akan memberi mereka hubungan internal, jadi variabel per unit terjemahan.

Bagaimana hubungan statis dengan hubungan variabel?

Ini memberi variabel namespace-lingkup hubungan internal. Ini memberikan anggota dan variabel lokal durasi penyimpanan statis.

Mari kita bahas semua ini:

//

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
}

Seluruh kata kunci statis ini benar-benar membingungkan

Tentunya, kecuali Anda sudah terbiasa dengannya. :) Mencoba menghindari menambahkan kata kunci baru ke bahasa, panitia menggunakan kembali yang ini, IMO, untuk efek ini - kebingungan. Ini digunakan untuk menandakan hal-hal yang berbeda (mungkin saya katakan, mungkin hal-hal yang berlawanan).


1
Biarkan saya meluruskan hal ini - Anda mengatakan bahwa ketika saya mengatakan static int xpada lingkup namespace, apakah itu memberikan penyimpanan non-statis ?
Michael Hagar

30

Untuk mengklarifikasi pertanyaan, saya lebih suka mengkategorikan penggunaan kata kunci 'statis' dalam tiga bentuk berbeda:

(SEBUAH). variabel

(B). fungsi

(C). variabel anggota / fungsi kelas

Penjelasan berikut di bawah ini untuk masing-masing sub judul:

(A) kata kunci 'statis' untuk variabel

Yang satu ini bisa sedikit rumit tetapi jika dijelaskan dan dipahami dengan benar, itu cukup mudah.

Untuk menjelaskan hal ini, pertama-tama sangat berguna untuk mengetahui tentang ruang lingkup, durasi dan keterkaitan variabel, yang tanpanya hal-hal selalu sulit dilihat melalui konsep keruh dari kata kunci staic

1. Cakupan : Menentukan di mana dalam file, variabel dapat diakses. Ini dapat terdiri dari dua jenis: (i) Lingkup Lokal atau Blok . (ii) Lingkup Global

2. Durasi : Menentukan kapan variabel dibuat dan dihancurkan. Sekali lagi ini dari dua jenis: (i) Durasi Penyimpanan Otomatis (untuk variabel yang memiliki cakupan Blok atau Lokal). (ii) Durasi Penyimpanan Statis (untuk variabel yang memiliki Cakupan Global atau variabel lokal (dalam suatu fungsi atau dalam blok kode) dengan statis ).

3. Tautan : Menentukan apakah suatu variabel dapat diakses (atau ditautkan) di file lain. Sekali lagi (dan untungnya) terdiri dari dua jenis: (i) Tautan Internal (untuk variabel yang memiliki Cakupan Blok dan Cakupan Global / Cakupan File / Cakupan Namespace Global) (ii) Tautan Eksternal (untuk variabel yang hanya memiliki Cakupan Global / Cakupan File / Ruang Lingkup Namespace Global)

Mari kita lihat contoh di bawah ini untuk pemahaman yang lebih baik tentang variabel global dan lokal polos (tidak ada variabel lokal dengan durasi penyimpanan statis):

//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

Kini hadir konsep Linkage. Ketika variabel global yang didefinisikan dalam satu file dimaksudkan untuk digunakan dalam file lain, keterkaitan variabel memainkan peran penting.

Tautan variabel global ditentukan oleh kata kunci: (i) statis , dan, (ii) eksternal

(Sekarang Anda mendapatkan penjelasannya)

kata kunci statis dapat diterapkan pada variabel dengan cakupan lokal dan global, dan dalam kedua kasus, keduanya memiliki arti yang berbeda. Pertama-tama saya akan menjelaskan penggunaan kata kunci 'statis' dalam variabel dengan cakupan global (di mana saya juga menjelaskan penggunaan kata kunci 'eksternal') dan kemudian untuk mereka yang memiliki cakupan lokal.

1. Kata Kunci Statis untuk variabel dengan cakupan global

Variabel global memiliki durasi statis, artinya mereka tidak keluar dari lingkup ketika blok kode tertentu (misalnya main ()) di mana ia digunakan berakhir. Bergantung pada tautan, mereka dapat diakses hanya di dalam file yang sama di mana mereka dideklarasikan (untuk variabel global statis), atau di luar file bahkan di luar file tempat mereka dideklarasikan (extern type global variable)

Dalam kasus variabel global yang memiliki extern specifier, dan jika variabel ini sedang diakses di luar file yang telah diinisialisasi, itu harus dideklarasikan ke depan dalam file di mana itu sedang digunakan, sama seperti fungsi harus maju menyatakan apakah definisi itu dalam file yang berbeda dari yang digunakan.

Sebaliknya, jika variabel global memiliki kata kunci statis, itu tidak dapat digunakan dalam file di luar yang telah dinyatakan.

(lihat contoh di bawah untuk klarifikasi)

misalnya:

//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;
}

sekarang setiap variabel dalam c ++ dapat berupa konst atau non-konst dan untuk setiap 'konstanta' kita mendapatkan dua case dari default c ++ linkage, jika tidak ada yang ditentukan:

(i) Jika variabel global adalah non-const, hubungannya dengan extern secara default , yaitu variabel global non-const dapat diakses dalam file .cpp lain dengan deklarasi maju menggunakan kata kunci extern (dengan kata lain, non const global variabel memiliki hubungan eksternal (dengan durasi statis tentu saja)). Juga penggunaan kata kunci extern dalam file asli di mana telah didefinisikan berlebihan. Dalam hal ini untuk membuat variabel global non-const tidak dapat diakses ke file eksternal, gunakan specifier 'statis' sebelum jenis variabel .

(ii) Jika variabel global adalah const, tautannya statis secara default , yaitu variabel global const tidak dapat diakses dalam file selain dari yang ditentukan, (dengan kata lain, variabel global const memiliki hubungan internal (dengan durasi statis tentu saja)). Juga penggunaan kata kunci statis untuk mencegah variabel global konst diakses dari file lain adalah berlebihan. Di sini, untuk membuat variabel global konst memiliki hubungan eksternal, gunakan specifier 'extern' sebelum jenis variabel

Berikut ini ringkasan untuk variabel lingkup global dengan berbagai tautan

//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

Selanjutnya kami menyelidiki bagaimana variabel global di atas berperilaku ketika diakses dalam file yang berbeda.

//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. Kata Kunci Statis untuk variabel dengan Lingkup Lokal

Pembaruan (Agustus 2019) pada kata kunci statis untuk variabel dalam cakupan lokal

Selanjutnya ini dapat dibagi lagi dalam dua kategori:

(i) kata kunci statis untuk variabel dalam blok fungsi , dan (ii) kata kunci statis untuk variabel dalam blok lokal yang tidak disebutkan namanya.

(i) kata kunci statis untuk variabel dalam blok fungsi.

Sebelumnya, saya menyebutkan bahwa variabel dengan cakupan lokal memiliki durasi otomatis, yaitu mereka muncul ketika blok dimasukkan (baik itu blok normal, baik itu blok fungsi) dan tidak ada lagi ketika blok berakhir, panjang cerita pendek, variabel dengan cakupan lokal memiliki durasi otomatis dan variabel durasi otomatis (dan objek) tidak memiliki hubungan yang berarti mereka tidak terlihat di luar blok kode.

Jika specifier statis diterapkan ke variabel lokal dalam blok fungsi, ia mengubah durasi variabel dari otomatis ke statis dan waktu hidup adalah seluruh durasi program yang berarti memiliki lokasi memori tetap dan nilainya diinisialisasi hanya sekali sebelum memulai program seperti yang disebutkan dalam referensi cpp (inisialisasi tidak boleh dikacaukan dengan penugasan)

mari kita lihat sebuah contoh.

//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;
}

Melihat kriteria di atas untuk variabel lokal statis dan variabel global statis, orang mungkin tergoda untuk bertanya, apa perbedaan di antara mereka. Sementara variabel global dapat diakses pada setiap titik di dalam kode (di sama serta unit terjemahan yang berbeda tergantung pada const -ness dan ekstern -ness), variabel statis didefinisikan dalam blok fungsi tidak langsung dapat diakses. Variabel harus dikembalikan oleh nilai fungsi atau referensi. Mari kita tunjukkan ini dengan sebuah contoh:

//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;
}

Penjelasan lebih lanjut tentang pilihan variabel lokal global dan statis statis dapat ditemukan di untaian stackoverflow ini

(ii) kata kunci statis untuk variabel dalam blok lokal yang tidak disebutkan namanya.

variabel statis dalam blok lokal (bukan blok fungsi) tidak dapat diakses di luar blok setelah blok lokal keluar dari ruang lingkup. Tidak ada peringatan untuk aturan ini.

    //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 memperkenalkan kata kunci constexpryang menjamin evaluasi ekspresi pada waktu kompilasi dan memungkinkan kompiler untuk mengoptimalkan kode. Sekarang jika nilai variabel const statis dalam lingkup diketahui pada waktu kompilasi, kode dioptimalkan dengan cara yang mirip dengan yang ada constexpr. Ini contoh kecil

Saya merekomendasikan pembaca juga untuk mencari perbedaan antara constexprdan static constuntuk variabel-variabel di thread stackoverflow ini . ini menyimpulkan penjelasan saya untuk kata kunci statis yang diterapkan pada variabel.

B. kata kunci 'statis' yang digunakan untuk fungsi

dalam hal fungsi, kata kunci statis memiliki makna langsung. Di sini, ini merujuk pada keterkaitan fungsi Biasanya semua fungsi yang dideklarasikan dalam file cpp memiliki hubungan eksternal secara default, yaitu fungsi yang didefinisikan dalam satu file dapat digunakan dalam file cpp lain dengan deklarasi maju.

menggunakan kata kunci statis sebelum deklarasi fungsi membatasi keterkaitannya dengan internal , yaitu fungsi statis tidak dapat digunakan dalam file di luar definisi.

C. Staitc Keyword yang digunakan untuk variabel anggota dan fungsi kelas

1. kata kunci 'statis' untuk variabel anggota kelas

Saya mulai langsung dengan contoh di sini

#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;
}

Dalam contoh ini, variabel statis m_designNum mempertahankan nilainya dan variabel anggota pribadi tunggal ini (karena statis) dibagikan dengan semua variabel tipe objek DesignNumber

Juga seperti variabel anggota lainnya, variabel anggota statis suatu kelas tidak terkait dengan objek kelas apa pun, yang ditunjukkan oleh pencetakan anyNumber di fungsi utama

variabel anggota statis vs non-const di kelas

(i) variabel anggota statis kelas non-const Dalam contoh sebelumnya anggota statis (baik publik dan pribadi) adalah konstanta non. Standar ISO melarang anggota statis non-const untuk diinisialisasi di kelas. Karenanya seperti pada contoh sebelumnya, mereka harus diinisialisasi setelah definisi kelas, dengan peringatan bahwa kata kunci statis perlu dihilangkan.

(ii) variabel anggota const-statis kelas ini mudah dan berjalan dengan konvensi inisialisasi variabel anggota konst, yaitu variabel anggota const statis kelas dapat diinisialisasi pada titik deklarasi dan mereka dapat diinisialisasi pada akhir deklarasi kelas dengan satu peringatan bahwa kata kunci const perlu ditambahkan ke anggota statis ketika diinisialisasi setelah definisi kelas.

Namun saya akan merekomendasikan untuk menginisialisasi variabel anggota const statis pada titik deklarasi. Ini berlaku dengan konvensi C ++ standar dan membuat kode terlihat lebih bersih

untuk lebih banyak contoh tentang variabel anggota statis di kelas, lihat tautan berikut dari learncpp.com http://www.learncpp.com/cpp-tutorial/811-static-member-variables/

2. kata kunci 'statis' untuk fungsi anggota kelas

Sama seperti variabel anggota kelas dapat, bersifat statis, demikian juga fungsi anggota kelas. Fungsi anggota normal dari kelas selalu dikaitkan dengan objek dari tipe kelas. Sebaliknya, fungsi anggota statis suatu kelas tidak terkait dengan objek kelas apa pun, yaitu mereka tidak memiliki * penunjuk ini.

Kedua karena fungsi anggota statis dari kelas tidak memiliki * penunjuk ini, mereka dapat dipanggil menggunakan nama kelas dan operator resolusi lingkup dalam fungsi utama (ClassName :: functionName ();)

Ketiga, fungsi anggota statis suatu kelas hanya dapat mengakses variabel anggota statis suatu kelas, karena variabel anggota non-statis suatu kelas harus dimiliki oleh objek kelas.

untuk lebih banyak contoh tentang fungsi anggota statis di kelas, lihat tautan berikut dari learncpp.com

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


1
1) Sebelum c ++ 17 hanya variabel konstanta konstanta integral yang dapat diinisialisasi di dalam kelas, misalnya struct Foo{static const std::string name = "cpp";};kesalahan, nameharus ditentukan di luar kelas; dengan variabel inline yang diintruksi dalam c ++ 17 kode dapat: struct Foo{static inline const std::string name = "cpp";};2) Fungsi anggota / anggota statis publik dapat diakses dengan nama kelas dengan operator resolusi lingkup dan juga sebuah instance dengan operator titik (misalnya: instance.some_static_method ())
oz1

Tidakkah seharusnya "m_anyVariable" menjadi "m_anyNumber"? dalam contoh kode terakhir Anda?
gebbissimo

Saya tidak bisa menilai kelengkapan dan kebenaran jawaban, tetapi tampaknya sangat komprehensif dan mudah diikuti. Terima kasih banyak! Jika Anda ingin memperbaikinya, ringkasan pendek di awal mungkin bermanfaat karena teksnya cukup panjang dan poin utama dapat dengan mudah divisualisasikan sebagai daftar bersarang atau diagram pohon untuk orang yang mengetahui istilah seperti "internal / eksternal linkage "
gebbissimo

18

Ini sebenarnya cukup sederhana. Jika Anda mendeklarasikan variabel sebagai statis dalam ruang lingkup fungsi, nilainya dipertahankan antara panggilan berturut-turut ke fungsi itu. Begitu:

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

akan ditampilkan 678alih-alih 666, karena ia mengingat nilai yang bertambah.

Adapun anggota statis, mereka mempertahankan nilainya di seluruh instance kelas. Jadi kode berikut:

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

akan mencetak 4, karena first.a dan second.a pada dasarnya adalah variabel yang sama. Adapun inisialisasi, lihat pertanyaan ini.


Ini tidak membahas variabel lingkup namespace.
Michael Hagar

10

Ketika Anda mendeklarasikan staticvariabel di lingkup berkas, maka itu variabel ini hanya tersedia di bahwa file tertentu (secara teknis, * unit terjemahan, tapi mari kita tidak menyulitkan ini terlalu banyak). Sebagai contoh:

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;
}

Untuk variabel lokal , staticberarti variabel tersebut akan diinisialisasi nol dan mempertahankan nilainya di antara panggilan:

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;
}

Untuk variabel kelas , itu berarti bahwa hanya ada satu contoh dari variabel yang dibagi di antara semua anggota kelas itu. Bergantung pada izin, variabel dapat diakses dari luar kelas menggunakan nama yang sepenuhnya memenuhi syarat.

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;
};

Menandai fungsi non-kelas sebagai static membuat fungsi hanya dapat diakses dari file itu dan tidak dapat diakses dari file lain.

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;
}

Untuk fungsi anggota kelas, menandainya sebagai staticfungsi yang tidak perlu dipanggil pada instance objek tertentu (yaitu tidak memiliki thispointer).

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

Variabel statis dibagi antara setiap instance dari kelas, bukannya setiap kelas memiliki variabel mereka sendiri.

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;

Setiap instance dari 'MyClass' memiliki 'myVar' mereka sendiri, tetapi berbagi 'myStaticVar' yang sama. Bahkan, Anda bahkan tidak memerlukan instance MyClass untuk mengakses 'myStaticVar', dan Anda dapat mengaksesnya di luar kelas seperti ini:

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

Ketika digunakan di dalam suatu fungsi sebagai variabel lokal (dan bukan sebagai variabel anggota kelas) kata kunci statis melakukan sesuatu yang berbeda. Ini memungkinkan Anda untuk membuat variabel persisten, tanpa memberikan lingkup global.

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;
}

Ini adalah variabel global dalam hal ketekunan ... tetapi tanpa menjadi global dalam cakupan / aksesibilitas.

Anda juga dapat memiliki fungsi anggota statis. Fungsi statis pada dasarnya adalah fungsi non-anggota, tetapi di dalam namespace nama kelas, dan dengan akses pribadi ke anggota kelas.

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;
}

Ketika Anda memanggil fungsi anggota, ada parameter tersembunyi yang disebut 'ini', yang merupakan pointer ke instance dari kelas yang memanggil fungsi. Fungsi anggota statis tidak memiliki parameter tersembunyi ... mereka dapat dipanggil tanpa instance kelas, tetapi juga tidak dapat mengakses variabel anggota non-statis kelas, karena mereka tidak memiliki pointer 'ini' untuk digunakan. Mereka tidak dipanggil pada instance kelas spesifik apa pun.


1
"Dengan asumsi itu dapat diakses oleh umum." - ini bukan.
Luchian Grigore

2
myStaticVarperlu didefinisikan juga. Agak penting untuk menyebutkan bahwa ketika menjawab pertanyaan tentang semantik statickata kunci, bukan begitu?
Praetorian

@Praetorian: Terima kasih, sudah diperbaiki.
Jamin Gray

1
@JaminGrey Dengan "static standalone" yang saya maksudkan adalah fungsi non-anggota statis, dan saya menulisnya kapan saja saya membutuhkan beberapa fungsionalitas baru hanya dalam file CPP saat ini, dan tidak ingin linker harus memproses simbol tambahan.
VR

1
@VR Aneh! Saya tidak pernah tahu bahwa fungsi itu ada. Terima kasih telah memperluas pengetahuan saya!
Jamin Gray

1

Saya bukan programmer C jadi saya tidak bisa memberi Anda informasi tentang penggunaan statis dalam program C dengan benar, tetapi ketika datang ke pemrograman berorientasi objek statis pada dasarnya mendeklarasikan variabel, atau fungsi atau kelas menjadi sama sepanjang kehidupan program. Ambil contoh.

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

Ketika Anda membuat instance kelas ini di Main Anda, Anda melakukan sesuatu seperti ini.

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

Dua instance kelas ini benar-benar berbeda satu sama lain dan beroperasi secara independen satu sama lain. Tetapi jika Anda membuat ulang kelas A seperti ini.

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

Ayo kembali ke main lagi.

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

Kemudian a1 dan a2 akan berbagi salinan int x yang sama dimana setiap operasi pada x dalam a1 akan secara langsung mempengaruhi operasi x dalam a2. Jadi jika saya melakukan ini

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
}

Kedua instance kelas A berbagi variabel dan fungsi statis. Semoga ini menjawab pertanyaan Anda. Pengetahuan saya yang terbatas tentang C memungkinkan saya untuk mengatakan bahwa mendefinisikan suatu fungsi atau variabel sebagai statis berarti hanya dapat dilihat oleh file yang fungsi atau variabelnya didefinisikan sebagai statis. Tetapi ini akan lebih baik dijawab oleh seorang pria C dan bukan saya. C ++ memungkinkan kedua cara C dan C ++ mendeklarasikan variabel Anda sebagai statis karena sepenuhnya kompatibel dengan C.


1

Apa artinya dengan variabel lokal? Apakah itu variabel fungsi lokal?

Ya - Non-global, seperti fungsi variabel lokal.

Karena ada juga yang ketika Anda mendeklarasikan fungsi lokal sebagai statis yang hanya diinisialisasi sekali, pertama kali masuk ke fungsi ini.

Baik.

Itu juga hanya berbicara tentang durasi penyimpanan berkenaan dengan anggota kelas, bagaimana dengan itu tidak spesifik contoh, itu juga properti dari statis tidak? Atau apakah itu durasi penyimpanan?

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

artinya, semua contoh Rpembagian int R::a- int R::atidak pernah disalin.

Sekarang bagaimana dengan kasing statis dan ruang lingkup file?

Secara efektif global yang memiliki konstruktor / penghancur jika diperlukan - inisialisasi tidak ditangguhkan hingga akses.

Bagaimana hubungan statis dengan hubungan variabel?

Untuk fungsi lokal, ini eksternal. Akses: Dapat diakses oleh fungsi (kecuali tentu saja, Anda mengembalikannya).

Untuk kelas, ini eksternal. Akses: Penentu akses standar berlaku (publik, dilindungi, pribadi).

static juga dapat menentukan hubungan internal, tergantung di mana itu dinyatakan (file / namespace).

Seluruh kata kunci statis ini benar-benar membingungkan

Ini memiliki terlalu banyak tujuan dalam C ++.

dapatkah seseorang mengklarifikasi kegunaan yang berbeda untuk bahasa Inggris dan juga memberi tahu saya kapan harus menginisialisasi anggota kelas statis?

Secara otomatis diinisialisasi sebelum mainjika dimuat dan memiliki konstruktor. Itu mungkin terdengar seperti hal yang baik, tetapi urutan inisialisasi sebagian besar di luar kendali Anda, jadi inisialisasi yang kompleks menjadi sangat sulit untuk dipertahankan, dan Anda ingin meminimalkan ini - jika Anda harus memiliki statis, maka fungsi skala lokal jauh lebih baik di perpustakaan dan proyek. Sejauh data dengan durasi penyimpanan statis, Anda harus mencoba meminimalkan desain ini, terutama jika dapat diubah (variabel global). Inisialisasi 'waktu' juga bervariasi karena sejumlah alasan - loader dan kernel memiliki beberapa trik untuk meminimalkan jejak memori dan menunda inisialisasi, tergantung pada data yang dimaksud.


1

Objek Statis: Kita dapat mendefinisikan anggota statis dengan kata kunci statis Ketika kita mendeklarasikan anggota kelas sebagai statis itu berarti tidak peduli berapa banyak objek kelas yang dibuat, hanya ada satu salinan anggota statis.

Anggota statis dibagikan oleh semua objek kelas. Semua data statis diinisialisasi ke nol ketika objek pertama dibuat, jika tidak ada inisialisasi lainnya. Kita tidak bisa memasukkannya ke dalam definisi kelas tetapi dapat diinisialisasi di luar kelas seperti yang dilakukan dalam contoh berikut dengan mendeklarasikan ulang variabel statis, menggunakan operator resolusi lingkup :: untuk mengidentifikasi kelas miliknya.

Mari kita coba contoh berikut untuk memahami konsep anggota data statis:

#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;
}

Ketika kode di atas dikompilasi dan dieksekusi, ia menghasilkan hasil sebagai berikut:

Constructor called.
Constructor called.
Total objects: 2

Anggota Fungsi Statis: Dengan mendeklarasikan anggota fungsi sebagai statis, Anda membuatnya independen dari objek tertentu dari kelas. Fungsi anggota statis dapat dipanggil bahkan jika tidak ada objek kelas dan fungsi statis diakses hanya menggunakan nama kelas dan operator resolusi ruang lingkup ::.

Fungsi anggota statis hanya dapat mengakses anggota data statis, fungsi anggota statis lainnya dan fungsi lainnya dari luar kelas.

Fungsi anggota statis memiliki cakupan kelas dan mereka tidak memiliki akses ke pointer kelas ini. Anda bisa menggunakan fungsi anggota statis untuk menentukan apakah beberapa objek kelas telah dibuat atau tidak.

Mari kita coba contoh berikut untuk memahami konsep anggota fungsi statis:

#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;
}

Ketika kode di atas dikompilasi dan dieksekusi, ia menghasilkan hasil sebagai berikut:

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

1
Akan benar untuk menyebutkan bahwa paradigma ini diambil dari tutorialspoint.com/cplusplus/cpp_static_members.htm
BugShotGG
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.