Làm thế nào để khởi tạo biến thành viên const trong một lớp?


105
#include <iostream>

using namespace std;
class T1
{
  const int t = 100;
  public:

  T1()
  {

    cout << "T1 constructor: " << t << endl;
  }
};

Khi tôi đang cố gắng khởi tạo biến thành viên const tvới 100. Nhưng nó mang lại cho tôi lỗi sau:

test.cpp:21: error: ISO C++ forbids initialization of member t
test.cpp:21: error: making t static

Làm cách nào để khởi tạo một constgiá trị?


8
với c ++ 11, có thể kiểm tra liên kết này stackoverflow.com/questions/13662441/…
Kapil,

Câu trả lời:


122

Các constquy định cụ thể biến dù một biến là sửa đổi hay không. Giá trị không đổi được gán sẽ được sử dụng mỗi khi biến được tham chiếu. Không thể sửa đổi giá trị được gán trong quá trình thực thi chương trình.

Lời giải thích của Bjarne Stroustrup tóm tắt nó một cách ngắn gọn:

Một lớp thường được khai báo trong tệp tiêu đề và tệp tiêu đề thường được đưa vào nhiều đơn vị dịch. Tuy nhiên, để tránh các quy tắc trình liên kết phức tạp, C ++ yêu cầu mọi đối tượng phải có một định nghĩa duy nhất. Quy tắc đó sẽ bị phá vỡ nếu C ++ cho phép định nghĩa trong lớp của các thực thể cần được lưu trữ trong bộ nhớ dưới dạng đối tượng.

Một constbiến phải được khai báo trong lớp, nhưng nó không thể được định nghĩa trong đó. Chúng ta cần xác định biến const bên ngoài lớp.

T1() : t( 100 ){}

Ở đây việc gán t = 100xảy ra trong danh sách trình khởi tạo, trước khi quá trình khởi tạo lớp xảy ra.


3
Bạn có thể giải thích một chút về tuyên bố cuối cùng Here the i = 10 assignment in initializer list happens much before the class initilizaiton occurs.mà tôi không hiểu được điều này. Và về cơ bản, loại định nghĩa cho phép trong lớp là trình biên dịch cụ thể phải không?
Chaitanya

3
Bài tập i = 10 là gì?
Daniel Daranas

Tôi có các hằng số trong lớp của mình mà tôi khởi tạo theo cách trên. Tuy nhiên, khi tôi cố gắng tạo một đối tượng của lớp đó, nó mang lại cho tôi lỗi nói rằng operator = function not foundtrong VC ++. Những gì có thể là vấn đề?
Rohit Shinde

4
Khi bạn sử dụng các từ chính xác của ai đó mà không cần ghi công, nó được gọi là đạo văn. Vui lòng sử dụng phân bổ thích hợp - xem stroustrup.com/bs_faq2.html#in-classstackoverflow.com/questions/13662441/…
Tanaya

Vâng, tôi cũng hoàn toàn không hiểu mã trong câu trả lời - đó là cái quái gì vậy? Nó có thể được đặt trong triển khai tệp cpp không?
Tomáš Zato - Phục hồi Monica

50

Chà, bạn có thể làm được static:

static const int t = 100;

hoặc bạn có thể sử dụng trình khởi tạo thành viên:

T1() : t(100)
{
    // Other constructor stuff here
}

2
Đối với mục đích sử dụng của anh ấy (và / hoặc ý định), sẽ tốt hơn nhiều nếu làm cho nó tĩnh.
Mark Garcia

@FredLarson Có giống như một số phiên bản g ++ không cho phép loại khởi tạo đó không? hoặc Nó hoàn toàn không được phép?
Chaitanya

3
@Chaitanya: C ++ 11 Bộ khởi tạo thành viên không tĩnh được triển khai từ gcc 4.7.
Jesse Good

@MarkGarcia tại sao tốt hơn nhiều? nó có thể được yêu cầu nếu const membercần được truy cập từ các chức năng / đối tượng thì tại sao lại tĩnh?
Asif Mushtaq

Mặc dù thông thường sẽ gây hiểu lầm khi đưa ra một ví dụ cho người mới bắt đầu về static. Bởi vì, họ có thể không biết nó chỉ là một cho tất cả các cá thể (đối tượng) của lớp đó.
Muhamed Cicak

30

Có một số cách để khởi tạo các thành viên const bên trong lớp ..

Định nghĩa thành viên const nói chung, cũng cần khởi tạo biến ..

1) Bên trong lớp, nếu bạn muốn khởi tạo const thì cú pháp như thế này

static const int a = 10; //at declaration

2) Cách thứ hai có thể

class A
{
  static const int a; //declaration
};

const int A::a = 10; //defining the static member outside the class

3) Nếu bạn không muốn khởi tạo lúc khai báo, thì cách khác là thông qua hàm tạo, biến cần được khởi tạo trong danh sách khởi tạo (không phải trong phần thân của hàm tạo). Nó phải như thế này

class A
{
  const int b;
  A(int c) : b(c) {} //const member initialized in initialization list
};

8
Tôi nghĩ câu trả lời này cần được làm rõ. Việc sử dụng từ khóa static cho một thành viên trong lớp không phải là thêm một số cú pháp tùy ý để làm cho trình biên dịch hài lòng. Nó có nghĩa là có một bản sao duy nhất của biến cho tất cả các trường hợp của đối tượng, không đổi hoặc không. Đó là một sự lựa chọn thiết kế cần được xem xét cẩn thận. Cuối cùng, lập trình viên có thể quyết định rằng thành viên lớp không đổi này vẫn có thể thay đổi với các đối tượng khác nhau, mặc dù vẫn không đổi trong suốt thời gian tồn tại của một đối tượng nhất định.
opetrenko,

Đã đồng ý ..Khi chúng ta sử dụng static, nó chỉ tạo một bản sao của nó cho tất cả các đối tượng .. Như bạn đã đề cập, nó là lựa chọn thiết kế. Trong trường hợp sao chép duy nhất cho tất cả các đối tượng 1 và 2 sẽ hoạt động. Trong trường hợp sao chép riêng cho từng đối tượng, 3 sẽ làm việc
ravs2627

Câu trả lời này gợi ý một thay đổi cú pháp đơn giản mà không gây hậu quả - trong khi thay đổi nó thành tĩnh thì không.
Isaac Woods

điều gì sẽ xảy ra nếu bạn cần sử dụng double hoặc float - đây có phải là một phần của tiêu chuẩn C ++ 11 không?
serup

14

Nếu bạn không muốn đặt constthành viên dữ liệu trong lớp là tĩnh, Bạn có thể khởi tạo constthành viên dữ liệu bằng cách sử dụng hàm tạo của lớp. Ví dụ:

class Example{
      const int x;
    public:
      Example(int n);
};

Example::Example(int n):x(n){
}

nếu có nhiều constthành viên dữ liệu trong lớp, bạn có thể sử dụng cú pháp sau để khởi tạo các thành viên:

Example::Example(int n, int z):x(n),someOtherConstVariable(z){}

3
Tôi nghĩ điều này cung cấp một câu trả lời tốt hơn câu trả lời đã được chấp nhận ....
Ian

1
Cảm ơn bạn vì những ví dụ rõ ràng như pha lê và biến thể hiển thị rất nhiều! Loại bỏ sự mơ hồ và nghiên cứu / cuộn thêm về phía người đọc!
clearlight

13
  1. Bạn có thể nâng cấp trình biên dịch của mình để hỗ trợ C ++ 11 và mã của bạn sẽ hoạt động hoàn hảo.

  2. Sử dụng danh sách khởi tạo trong phương thức khởi tạo.

    T1() : t( 100 )
    {
    }

6

Một giải pháp khác là

class T1
{
    enum
    {
        t = 100
    };

    public:
    T1();
};

Vì vậy, t được khởi tạo thành 100 và nó không thể thay đổi được và nó là private.


3

Nếu một thành viên là một Mảng, nó sẽ phức tạp hơn một chút so với bình thường là:

class C
{
    static const int ARRAY[10];
 public:
    C() {}
};
const unsigned int C::ARRAY[10] = {0,1,2,3,4,5,6,7,8,9};

hoặc là

int* a = new int[N];
// fill a

class C {
  const std::vector<int> v;
public:
  C():v(a, a+N) {}
};

2

Một cách khác có thể là không gian tên:

#include <iostream>

namespace mySpace {
   static const int T = 100; 
}

using namespace std;

class T1
{
   public:
   T1()
   {
       cout << "T1 constructor: " << mySpace::T << endl;
   }
};

Điểm bất lợi là các lớp khác cũng có thể sử dụng hằng số nếu chúng bao gồm tệp tiêu đề.


1

Đây là cách làm đúng. Bạn có thể thử mã này.

#include <iostream>

using namespace std;

class T1 {
    const int t;

    public:
        T1():t(100) {
            cout << "T1 constructor: " << t << endl;
        }
};

int main() {
    T1 obj;
    return 0;
}

nếu bạn đang sử dụng C++10 Compiler or belowthì bạn không thể khởi tạo thành viên khuyết điểm tại thời điểm khai báo. Vì vậy, ở đây nó phải tạo hàm tạo để khởi tạo thành viên dữ liệu const. Nó cũng phải sử dụng danh sách khởi tạo T1():t(100)để có bộ nhớ ngay lập tức.


0

bạn có thể thêm staticđể có thể khởi tạo biến thành viên lớp này.

static const int i = 100;

Tuy nhiên, đây không phải lúc nào cũng là một thông lệ tốt để sử dụng khai báo lớp bên trong, vì tất cả các đối tượng được cài đặt từ lớp đó sẽ chia sẻ cùng một biến tĩnh được lưu trữ trong bộ nhớ trong bên ngoài phạm vi bộ nhớ của các đối tượng được khởi tạo.

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.