Biến tĩnh trong hàm thành viên


158

Ai đó có thể giải thích làm thế nào các biến tĩnh trong các hàm thành viên hoạt động trong C ++.

Cho lớp sau:

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

Nếu tôi khai báo nhiều trường hợp A, việc gọi foo()trên một thể hiện có làm tăng biến tĩnh itrên tất cả các trường hợp không? Hay chỉ có một cái nó được gọi là?

Tôi giả định rằng mỗi trường hợp sẽ có bản sao riêng i, nhưng bước qua một số mã tôi dường như chỉ ra điều khác.

Câu trả lời:


169

class Alà một lớp không phải là khuôn mẫu và A::foo()là một hàm không phải là khuôn mẫu. Sẽ chỉ có một bản sao static int ibên trong chương trình.

Bất kỳ trường hợp nào của Ađối tượng sẽ ảnh hưởng như nhau ivà thời gian tồn tại của ichương trình. Để thêm một ví dụ:

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

3
Cảm ơn tấm gương tốt! Liệu có cách nào để thực sự đạt được một cái gì đó làm cho phạm vi static int icụ thể của thể hiện, ví dụ như vậy o1.foo(); // i = 1$o2.foo(); // i = 1...?
Cá đuối

14
Mặc dù đây có thể không phải là phong cách mà bạn đang tìm kiếm, làm cho thành viên dữ liệu riêng tư của lớp A sẽ có hiệu ứng mà bạn đang mô tả. Nếu bạn lo ngại về xung đột tên, bạn có thể thêm tiền tố như m_để chỉ trạng thái của i.
Carl Morris

137

Không staticmay từ khóa có một vài ý nghĩa không liên quan khác nhau trong C ++

  1. Khi được sử dụng cho các thành viên dữ liệu, điều đó có nghĩa là dữ liệu đó là phân bổ trong lớp chứ không phải trong các trường hợp.

  2. Khi được sử dụng cho dữ liệu bên trong một chức năng, điều đó có nghĩa là dữ liệu được phân bổ tĩnh, khởi tạo lần đầu tiên khối được nhập và tồn tại cho đến khi chương trình thoát. Ngoài ra biến chỉ hiển thị bên trong hàm. Tính năng đặc biệt này của các thống kê địa phương thường được sử dụng để thực hiện việc xây dựng các singletons lười biếng.

  3. Khi được sử dụng ở cấp đơn vị biên dịch (mô-đun), điều đó có nghĩa là biến đó giống như toàn cục (nghĩa là được phân bổ và khởi tạo trước mainđược chạy và hủy sau khi mainthoát) nhưng biến đó sẽ không thể truy cập hoặc hiển thị trong các đơn vị biên dịch khác .

Tôi đã thêm một số nhấn mạnh vào phần quan trọng nhất cho mỗi lần sử dụng. Sử dụng (3) có phần không được khuyến khích trong các không gian tên không tên cũng cho phép khai báo lớp chưa xuất.

Trong mã của bạn, statictừ khóa được sử dụng với nghĩa số 2 và không liên quan gì đến các lớp hoặc thể hiện ... đó là một biến của hàm và sẽ chỉ có một bản sao của nó.

Như chính xác, iammilind đã nói tuy nhiên có thể có nhiều trường hợp của biến đó nếu hàm là hàm mẫu (vì trong trường hợp đó thực sự chính hàm đó có thể có trong nhiều bản sao khác nhau trong chương trình). Ngay cả trong trường hợp đó, các lớp và các khóa học không liên quan ... xem ví dụ sau:

#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 cho keyword static unfortunately has a few different unrelated meanings in C++:)
iammilind

thế giới có ý nghĩa hơn rất nhiều sau khi đọc nó, CẢM ƠN BẠN
Erin

Tôi thích các mẹo với các mẫu. Tôi không thể chờ đợi để tìm một cái cớ để sử dụng nó.
Tomáš Zato - Phục hồi Monica

Bất cứ ai cũng có một tài liệu tham khảo cho "hơi nản lòng ủng hộ các không gian tên không tên"?
austinmarton

3
@austinmarton: Cụm từ "Việc sử dụng tĩnh để biểu thị 'đơn vị dịch thuật cục bộ' không được dùng trong C ++. Thay vào đó, hãy sử dụng các không gian tên không tên (8.2.5.1)" tại trang 819.
6502

2

Biến tĩnh bên trong hàm

  • Biến tĩnh được tạo bên trong một hàm được lưu trữ trên bộ nhớ tĩnh của chương trình chứ không phải trên ngăn xếp.

  • Khởi tạo biến tĩnh sẽ được thực hiện trong lệnh gọi đầu tiên của hàm.

  • Biến tĩnh sẽ giữ lại giá trị trong nhiều lệnh gọi hàm

  • Thời gian tồn tại của biến tĩnh là Chương trình

nhập mô tả hình ảnh ở đây

Ví dụ

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

Đầu ra:

Biến tĩnh

Giá trị biến: 0
Giá trị biến: 1
Giá trị biến: 2
Giá trị biến: 3
Giá trị biến: 4

Biến tự động

Giá trị biến: 0
Giá trị biến: 0
Giá trị biến: 0
Giá trị biến: 0
Giá trị biến: 0


-2

Câu trả lời đơn giản:

Các biến tĩnh, bất kể chúng là thành viên của hàm (không templated) classhay hàm (không templated), hoạt động - về mặt kỹ thuật - giống như một nhãn toàn cầu có phạm vi giới hạn cho classhàm hoặc hàm.


9
Số Globals được khởi tạo khi khởi động chương trình, trạng thái chức năng được khởi tạo ở lần sử dụng đầu tiên. Đây là một sự khác biệt lớn .
6502

Tôi không nghĩ đây là những gì xảy ra. Tuy nhiên, điều này nên được trình biên dịch cụ thể nào.
0xbadf00d

2
Sau đó, bạn nghĩ sai: 3.6.1 trong tiêu chuẩn C ++ ra lệnh rằng việc xây dựng đối tượng của phạm vi không gian tên với thời gian lưu trữ tĩnh xảy ra khi khởi động; 6.7 (4) ra lệnh rằng nói chung "... một biến như vậy được khởi tạo khi điều khiển lần đầu tiên đi qua khai báo của nó; một biến như vậy được coi là khởi tạo khi hoàn thành khởi tạo". Bằng cách này, việc khởi tạo lần đầu tiên này rất thuận tiện để thực hiện việc xây dựng đơn lẻ lười biếng.
6502

3.7.4: "Khởi tạo liên tục (3.6.2) của thực thể phạm vi khối với thời gian lưu trữ tĩnh, nếu có, được thực hiện trước khi khối đầu tiên được nhập. Việc triển khai được phép thực hiện khởi tạo sớm các biến phạm vi khối khác với Thời lượng lưu trữ tĩnh hoặc luồng trong cùng điều kiện triển khai được phép khởi tạo tĩnh một biến có thời lượng lưu trữ tĩnh hoặc luồng trong phạm vi không gian tên (3.6.2). Nếu không, biến đó được khởi tạo điều khiển lần đầu tiên đi qua khai báo của nó; "
0xbadf00d

1
Tuy nhiên, đủ tò mò: 1) để khởi tạo liên tục, không cần phải thảo luận nếu một tĩnh cục bộ có thể được khởi tạo trước khi vào khối lần đầu tiên (biến chỉ hiển thị bên trong khối và khởi tạo liên tục không tạo ra tác dụng phụ); 2) không có gì trong bài viết của bạn được nói về khởi tạo liên tục; 3) thống kê cục bộ rất hữu ích cho việc khởi tạo không liên tục như MyClass& instance(){ static MyClass x("config.ini"); return x; }- một triển khai di động hợp lệ cho việc sử dụng một luồng chính xác bởi vì các thống kê cục bộ KHÔNG đơn giản giống như toàn cầu bất chấp những gì bạn nói.
6502
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.