วิธีการเริ่มต้นตัวแปร const member ในคลาส?


107
#include <iostream>

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

  T1()
  {

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

เมื่อฉันพยายามเริ่มต้นตัวแปรสมาชิก const tด้วย 100 แต่มันทำให้ฉันมีข้อผิดพลาดต่อไปนี้:

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

ฉันจะเริ่มต้นconstค่าได้อย่างไร


8
ด้วย c ++ 11 สามารถตรวจสอบลิงค์นี้stackoverflow.com/questions/13662441/…
Kapil

คำตอบ:


124

constระบุว่าตัวแปรตัวแปรคือแก้ไขได้หรือไม่ ค่าคงที่ที่กำหนดจะถูกใช้ทุกครั้งที่มีการอ้างอิงตัวแปร ค่าที่กำหนดไม่สามารถแก้ไขได้ระหว่างการทำงานของโปรแกรม

คำอธิบายของ Bjarne Stroustrup สรุปได้สั้น ๆ :

โดยทั่วไปคลาสจะถูกประกาศในไฟล์ส่วนหัวและโดยทั่วไปไฟล์ส่วนหัวจะรวมอยู่ในหน่วยการแปลจำนวนมาก อย่างไรก็ตามเพื่อหลีกเลี่ยงกฎตัวเชื่อมโยงที่ซับซ้อน C ++ ต้องการให้ทุกออบเจ็กต์มีนิยามเฉพาะ กฎนั้นจะเสียหาก C ++ อนุญาตให้มีการกำหนดเอนทิตีในคลาสที่จำเป็นต้องเก็บไว้ในหน่วยความจำเป็นวัตถุ

ต้องconstมีการประกาศตัวแปรภายในคลาส แต่ไม่สามารถกำหนดได้ เราจำเป็นต้องกำหนดตัวแปร const นอกคลาส

T1() : t( 100 ){}

ที่นี่งานt = 100จะเกิดขึ้นในรายการ initializer ก่อนที่การเริ่มชั้นเรียนจะเกิดขึ้น


3
คุณสามารถอธิบายรายละเอียดเกี่ยวกับข้อความสุดท้ายที่Here the i = 10 assignment in initializer list happens much before the class initilizaiton occurs.ฉันได้รับนี้ และโดยพื้นฐานแล้วการอนุญาตให้คำจำกัดความภายในคลาสเป็นคอมไพเลอร์เฉพาะใช่ไหม
Chaitanya

3
สิ่งที่ฉัน = 10 การมอบหมาย?
Daniel Daranas

ฉันมีค่าคงที่ในชั้นเรียนซึ่งฉันเริ่มต้นด้วยวิธีข้างต้น อย่างไรก็ตามเมื่อฉันพยายามสร้างออบเจ็กต์ของคลาสนั้นมันทำให้ฉันมีข้อผิดพลาดที่บอกว่าoperator = function not foundใน VC ++ อะไรคือปัญหา?
Rohit Shinde

4
เมื่อคุณใช้คำพูดของใครบางคนโดยไม่มีการระบุแหล่งที่มาจะเรียกว่าการลอกเลียนแบบ โปรดใช้การระบุแหล่งที่มาที่เหมาะสม - ดูstroustrup.com/bs_faq2.html#in-classและstackoverflow.com/questions/13662441/…
Tanaya

ใช่ฉันยังไม่เข้าใจรหัสในคำตอบโดยสิ้นเชิงนั่นคืออะไร? สามารถวางในการใช้งานไฟล์ cpp ได้หรือไม่?
Tomáš Zato - คืนสถานะ Monica

51

คุณสามารถทำได้static:

static const int t = 100;

หรือคุณสามารถใช้ตัวเริ่มต้นสมาชิก:

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

2
สำหรับการใช้งานของเขา (และ / หรือความตั้งใจ) มันจะดีกว่ามากถ้าจะทำให้มันคงที่
Mark Garcia

@FredLarson เหมือนกับว่ารุ่น g ++ บางรุ่นไม่อนุญาตให้มีการเริ่มต้นแบบนั้นหรือไม่? หรือไม่ได้รับอนุญาตเลย?
Chaitanya

3
@Chaitanya: C ++ 11 ตัวเริ่มต้นสมาชิกแบบไม่คงที่ถูกนำมาใช้จาก gcc 4.7
Jesse Good

@MarkGarcia ทำไมดีขึ้นมาก อาจเป็นไปตามข้อกำหนดหากconst memberควรเข้าถึงได้จากฟังก์ชั่น / วัตถุแล้วทำไมคงที่
Asif Mushtaq

แม้ว่าโดยปกติแล้วจะทำให้เข้าใจผิดในการยกตัวอย่างให้กับผู้เริ่มต้นใช้งานแบบคงที่ เนื่องจากพวกเขาอาจไม่รู้ว่าเป็นเพียงอินสแตนซ์ (อ็อบเจ็กต์) ทั้งหมดของคลาสนั้น
Muhamed Cicak

30

มีสองวิธีในการเริ่มต้นสมาชิก const ในชั้นเรียน ..

คำจำกัดความของสมาชิก const โดยทั่วไปต้องการการเริ่มต้นของตัวแปรด้วย ..

1) ภายในคลาสถ้าคุณต้องการเริ่มต้น const ไวยากรณ์จะเป็นเช่นนี้

static const int a = 10; //at declaration

2) วิธีที่สองสามารถ

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

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

3) ถ้าคุณไม่ต้องการเริ่มต้นที่การประกาศอีกวิธีหนึ่งคือการผ่านตัวสร้างตัวแปรจะต้องถูกเตรียมใช้งานในรายการการเริ่มต้น (ไม่ใช่ในเนื้อหาของตัวสร้าง) มันต้องเป็นแบบนี้

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

9
ฉันคิดว่าคำตอบนี้ต้องการคำชี้แจง การใช้คีย์เวิร์ดแบบคงที่สำหรับสมาชิกคลาสไม่ใช่การเพิ่มไวยากรณ์ตามอำเภอใจเพื่อทำให้คอมไพเลอร์พอใจ หมายความว่ามีสำเนาเดียวของตัวแปรสำหรับอินสแตนซ์ทั้งหมดของอ็อบเจ็กต์คงที่หรือไม่ เป็นทางเลือกในการออกแบบที่ต้องพิจารณาอย่างรอบคอบ ในบรรทัดโปรแกรมเมอร์อาจตัดสินใจว่าสมาชิกคลาสคงที่นี้อาจยังคงแปรผันตามวัตถุต่าง ๆ แม้จะยังคงมีค่าคงที่ตลอดอายุการใช้งานของวัตถุที่กำหนด
opetrenko

เห็นด้วย .. เมื่อเราใช้แบบคงที่มันจะสร้างสำเนาเพียงชุดเดียวสำหรับวัตถุทั้งหมด .. ดังที่คุณกล่าวถึงตัวเลือกการออกแบบ ในกรณีของสำเนาเดียวสำหรับวัตถุทั้งหมด 1 และ 2 ควรใช้งานได้ ในกรณีของสำเนาเดี่ยวสำหรับแต่ละวัตถุ 3 จะใช้งานได้
ravs2627

คำตอบนี้แสดงให้เห็นถึงการเปลี่ยนแปลงไวยากรณ์อย่างง่ายโดยไม่มีผล - ในขณะที่การเปลี่ยนเป็นแบบคงที่ไม่ได้
Isaac Woods

จะเกิดอะไรขึ้นถ้าคุณต้องใช้ double หรือ float - นี่เป็นส่วนหนึ่งของมาตรฐาน C ++ 11 หรือไม่?
serup

14

หากคุณไม่ต้องการทำให้constสมาชิกข้อมูลอยู่ในคลาสคงที่คุณสามารถเตรียมconstข้อมูลเบื้องต้นให้กับสมาชิกข้อมูลโดยใช้ตัวสร้างของคลาส ตัวอย่างเช่น:

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

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

หากมีconstสมาชิกข้อมูลหลายคนในคลาสคุณสามารถใช้ไวยากรณ์ต่อไปนี้เพื่อเริ่มต้นสมาชิก:

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

3
ฉันคิดว่านี่ให้คำตอบที่ดีกว่าคำตอบที่ยอมรับ ....
Ian

1
ขอบคุณสำหรับตัวอย่างที่ชัดเจนและตัวแปรที่แสดงความหลากหลาย! ขจัดความคลุมเครือและการค้นคว้าเพิ่มเติม / การเลื่อนในส่วนของผู้อ่าน!
clearlight

13
  1. คุณสามารถอัพเกรดคอมไพเลอร์ของคุณเพื่อรองรับ C ++ 11 และโค้ดของคุณจะทำงานได้อย่างสมบูรณ์

  2. ใช้รายการเริ่มต้นในตัวสร้าง

    T1() : t( 100 )
    {
    }

6

อีกวิธีหนึ่งคือ

class T1
{
    enum
    {
        t = 100
    };

    public:
    T1();
};

ดังนั้น t จึงเริ่มต้นเป็น 100 และไม่สามารถเปลี่ยนแปลงได้และเป็นแบบส่วนตัว


3

หากสมาชิกเป็น Array มันจะซับซ้อนกว่าปกติเล็กน้อยคือ:

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

หรือ

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

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

2

อีกวิธีหนึ่งที่เป็นไปได้คือเนมสเปซ:

#include <iostream>

namespace mySpace {
   static const int T = 100; 
}

using namespace std;

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

ข้อเสียคือคลาสอื่น ๆ ยังสามารถใช้ค่าคงที่ได้หากรวมไฟล์ส่วนหัวไว้ด้วย


1

นี่เป็นวิธีที่เหมาะสมที่จะทำ คุณสามารถลองใช้รหัสนี้

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

หากคุณใช้งานอยู่C++10 Compiler or belowคุณจะไม่สามารถเริ่มต้นสมาชิกข้อเสียได้ในขณะที่ประกาศ ดังนั้นที่นี่จึงต้องสร้างตัวสร้างเพื่อเริ่มต้นสมาชิกข้อมูล const นอกจากนี้ยังต้องใช้รายการเริ่มต้นT1():t(100)เพื่อรับหน่วยความจำในทันที


0

คุณสามารถเพิ่มstaticเพื่อทำให้การกำหนดค่าเริ่มต้นของตัวแปรสมาชิกคลาสนี้เป็นไปได้

static const int i = 100;

อย่างไรก็ตามนี่ไม่ใช่แนวทางปฏิบัติที่ดีเสมอไปในการใช้การประกาศคลาสภายในเนื่องจากอ็อบเจ็กต์ทั้งหมดที่ติดตั้งจากคลาสนั้นจะแชร์ตัวแปรคงที่เดียวกันซึ่งเก็บไว้ในหน่วยความจำภายในภายนอกหน่วยความจำขอบเขตของอ็อบเจ็กต์ที่สร้างอินสแตนซ์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.