เหตุใดฟังก์ชันสมาชิก const จึงสามารถแก้ไขสมาชิกข้อมูลคงที่ได้


86

ในC++โปรแกรมต่อไปนี้การแก้ไขสมาชิกข้อมูลแบบคงที่จากconstฟังก์ชันทำงานได้ดี:

class A 
{
  public:   
    static int a; // static data member

    void set() const
    {
        a = 10;
    }
};

แต่การแก้ไขสมาชิกข้อมูลที่ไม่คงที่จากconstฟังก์ชันไม่ทำงาน:

class A 
{
  public:   
    int a; // non-static data member

    void set() const
    {
        a = 10;
    }
};

เหตุใดconstฟังก์ชันสมาชิกจึงสามารถแก้ไขstaticสมาชิกข้อมูลได้


จะเป็นประโยชน์ถ้าคุณสามารถบอกเราได้ว่าคุณกำลังทำงานกับแพลตฟอร์มและคอมไพเลอร์ใด ดังนั้นเราจึงสามารถระบุได้ว่าพฤติกรรมนั้นเป็นจุดบกพร่องที่เกี่ยวข้องกับการตั้งค่าเฉพาะของคุณหรือว่าพฤติกรรมนั้นถูกต้องจริง ๆ และจำเป็นต้องอธิบาย
Alex Zywicki

@AlexZywicki G ++ คอมไพเลอร์บนแพลตฟอร์ม Linux
msc

8
ไม่จำเป็น. เป็นความตั้งใจและคอมไพเลอร์ C ++ ทั้งหมดต้องรองรับ แต่ทำไมคำถามดีๆแบบนี้ถึงไม่ได้รับการโหวตอีกต่อไป?
Bathsheba

18
มันหลอกลวง แต่เขียนได้ดีกว่าอีกอันด้วย MCVE ที่ดีกว่าฉันจึงใช้สิ่งนี้เป็นเป้าหมาย
Baum mit Augen

5
แรงจูงใจในที่นี้constหมายถึงฟังก์ชันสมาชิกของวัตถุไม่สามารถแก้ไขวัตถุนั้นได้ มันสามารถปรับเปลี่ยนออบเจ็กต์อื่น ๆ ของคลาสเดียวกันหรือstaticข้อมูลที่เชื่อมโยงกับคลาสไม่ใช่อินสแตนซ์ใด ๆ ของมัน (หรือmutableสมาชิกข้อมูลที่สร้างขึ้นเพื่อเป็นข้อยกเว้นของกฎนี้)
Davislor

คำตอบ:


100

เป็นกฎนั่นคือทั้งหมด และด้วยเหตุผลที่ดี

constรอบคัดเลือกในฟังก์ชันสมาชิกหมายความว่าคุณไม่สามารถแก้ไขไม่ใช่mutableไม่ใช่staticตัวแปรสมาชิกชั้น

โดยวิธีการเสนอการหาเหตุผลเข้าข้างตนเองthisตัวชี้ในconstฟังก์ชันสมาชิกที่มีคุณสมบัติเหมาะสมคือconstประเภทและthisเกี่ยวข้องโดยเนื้อแท้กับอินสแตนซ์ของคลาส staticสมาชิกไม่เกี่ยวข้องกับอินสแตนซ์คลาส คุณไม่จำเป็นเช่นการปรับเปลี่ยนstaticสมาชิก: A::a = 10;คุณสามารถทำมันได้ในกรณีของคุณโดยการเขียน

ดังนั้นในกรณีแรกของคุณคิดว่าa = 10;เป็นชวเลขA::a = 10;และในกรณีที่สองคิดว่ามันเป็นชวเลขthis->a = 10;ซึ่งไม่ compilable ตั้งแต่ประเภทของการมีthisconst A*


1
เพียงแค่ข้อผิดพลาดเล็กน้อยที่นี่: เนื่องจากคุณไม่สามารถกำหนดใหม่thisชี้ว่ามันจะเป็นชนิดconst A* const ในconstกรณีของ
เทย์เลอร์แฮนเซน

2
@TaylorHansen thisเป็น prvalue ของประเภทตัวชี้ Prvalues ​​ของประเภทที่ไม่ใช่คลาสจะไม่ผ่านการรับรอง CV

21

ตามมาตรฐาน C ++ (9.2.3.2 สมาชิกข้อมูลคงที่)

1 สมาชิกข้อมูลคงที่ไม่ได้เป็นส่วนหนึ่งของวัตถุย่อยของคลาส ...

และ (9.2.2.1 ตัวชี้นี้)

1 ในเนื้อความของฟังก์ชันสมาชิกที่ไม่คงที่ (9.2.1) คีย์เวิร์ดนี้คือนิพจน์ prvalue ที่มีค่าเป็นแอดเดรสของอ็อบเจ็กต์ที่ฟังก์ชันถูกเรียกใช้ ประเภทนี้ในฟังก์ชันสมาชิกของคลาส X คือ X *หากประกาศฟังก์ชันสมาชิก const ประเภทนี้คือ const X * , ...

และในที่สุด (9.2.2 ฟังก์ชันสมาชิกไม่คงที่)

3 ... ถ้าการค้นหาชื่อ (3.4) แก้ไขชื่อในนิพจน์ id เป็นสมาชิกที่ไม่ใช่ประเภทที่ไม่คงที่ของคลาส C บางตัวและถ้านิพจน์ id อาจได้รับการประเมินหรือ C เป็น X หรือคลาสฐาน ของ X นิพจน์ id จะถูกแปลงเป็นนิพจน์การเข้าถึงสมาชิกคลาส (5.2.5) โดยใช้(* this) (9.2.2.1) เป็นนิพจน์ postfix ทางด้านซ้ายของ. ตัวดำเนินการ

ดังนั้นในนิยามคลาสนี้

class A 
{
  public:   
    static int a; 

    void set() const
    {
        a = 10;
    }
};

สมาชิกข้อมูลคงที่ aไม่ใช่วัตถุย่อยของอ็อบเจ็กต์ประเภทคลาสและthisไม่ใช้ตัวชี้เพื่อเข้าถึงสมาชิกข้อมูลแบบคงที่ ดังนั้นฟังก์ชันสมาชิกใด ๆ ค่าคงที่ไม่คงที่หรือไม่คงที่หรือฟังก์ชันสมาชิกคงที่สามารถเปลี่ยนสมาชิกข้อมูลได้เนื่องจากไม่ใช่ค่าคงที่

ในนิยามคลาสนี้

class A 
{
  public:   
    int a; 

    void set() const
    {
        a = 10;
    }
};

สมาชิกข้อมูลที่ไม่คงที่aเป็นวัตถุย่อยของวัตถุประเภทคลาส ในการเข้าถึงมันในฟังก์ชันสมาชิกมีการใช้ไวยากรณ์การเข้าถึงสมาชิกของไวยากรณ์นี้โดยนัย คุณไม่สามารถใช้ตัวชี้ค่าคงที่thisเพื่อแก้ไขสมาชิกข้อมูล และตัวชี้นี้ย่อมมีประเภทconst A *ที่อยู่ในการทำงานเพราะฟังก์ชั่นที่มีการประกาศด้วยรอบคัดเลือกset constหากฟังก์ชันไม่มีคุณสมบัติในกรณีนี้สมาชิกข้อมูลสามารถเปลี่ยนแปลงได้


13

สิ่งนี้ก็คือถ้าฟังก์ชันสมาชิกของคลาสAเป็นconstประเภทของthisคือconst X*และด้วยเหตุนี้จึงป้องกันไม่ให้สมาชิกข้อมูลที่ไม่คงที่ถูกเปลี่ยนแปลง (cf เช่นมาตรฐาน C ++ ):

9.3.2 ตัวชี้นี้ [class.this]

ในเนื้อความของฟังก์ชันสมาชิกที่ไม่คงที่ (9.3) คีย์เวิร์ดนี้คือนิพจน์ prvalue ที่มีค่าเป็นแอดเดรสของอ็อบเจ็กต์ที่ฟังก์ชันถูกเรียกใช้ ประเภทนี้ในฟังก์ชันสมาชิกของคลาส X คือ X * หากประกาศฟังก์ชันสมาชิก const ประเภทนี้คือ const X *, ...

หากaเป็นสมาชิกข้อมูลไม่คงที่แล้วa=10เป็นเช่นเดียวกับthis->a = 10ที่ไม่ได้รับอนุญาตหากประเภทของthisเป็นconst A*และไม่ได้รับการประกาศให้เป็นa mutableดังนั้นตั้งแต่void set() constทำให้ประเภทของthisความเป็นอยู่const A*, การเข้าถึงนี้ไม่ได้รับอนุญาต

ถ้าaเป็นสมาชิกข้อมูลแบบคงที่ตรงกันข้ามa=10จะไม่มีส่วนเกี่ยวข้องthisเลย และตราบใดที่static int aยังไม่ได้รับการประกาศว่าเป็นconstคำสั่งa=10อนุญาต


1

constรอบคัดเลือกในฟังก์ชันสมาชิกหมายความว่าคุณไม่สามารถแก้ไขnon-mutable, ข้อมูลสมาชิกระดับnon-static

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