ความหมายของ 'const' สุดท้ายในการประกาศฟังก์ชั่นของชั้นเรียนหรือไม่?


คำตอบ:


951

เมื่อคุณเพิ่มconstคำสำคัญให้กับวิธีการthisตัวชี้จะกลายเป็นตัวชี้ไปยังconstวัตถุและคุณไม่สามารถเปลี่ยนข้อมูลสมาชิกใด ๆ (ยกเว้นว่าคุณใช้mutableมากขึ้นในภายหลัง)

constคำหลักที่เป็นส่วนหนึ่งของลายเซ็นของฟังก์ชั่นซึ่งหมายความว่าคุณสามารถใช้สองวิธีการที่คล้ายกันหนึ่งซึ่งเรียกว่าเมื่อวัตถุอยู่constและคนที่ไม่ได้เป็น

#include <iostream>

class MyClass
{
private:
    int counter;
public:
    void Foo()
    { 
        std::cout << "Foo" << std::endl;    
    }

    void Foo() const
    {
        std::cout << "Foo const" << std::endl;
    }

};

int main()
{
    MyClass cc;
    const MyClass& ccc = cc;
    cc.Foo();
    ccc.Foo();
}

สิ่งนี้จะออก

Foo
Foo const

ในวิธีที่ไม่ใช่ const คุณสามารถเปลี่ยนสมาชิกอินสแตนซ์ซึ่งคุณไม่สามารถทำได้ในconstรุ่น หากคุณเปลี่ยนวิธีการประกาศในตัวอย่างข้างต้นเป็นรหัสด้านล่างคุณจะได้รับข้อผิดพลาดบางอย่าง

    void Foo()
    {
        counter++; //this works
        std::cout << "Foo" << std::endl;    
    }

    void Foo() const
    {
        counter++; //this will not compile
        std::cout << "Foo const" << std::endl;
    }

สิ่งนี้ไม่เป็นความจริงอย่างสมบูรณ์เพราะคุณสามารถทำเครื่องหมายสมาชิกว่าmutableและconstวิธีการนั้นสามารถเปลี่ยนแปลงได้ ส่วนใหญ่จะใช้สำหรับเคาน์เตอร์ภายในและสิ่งของ ทางออกสำหรับการที่จะเป็นรหัสด้านล่าง

#include <iostream>

class MyClass
{
private:
    mutable int counter;
public:

    MyClass() : counter(0) {}

    void Foo()
    {
        counter++;
        std::cout << "Foo" << std::endl;    
    }

    void Foo() const
    {
        counter++;    // This works because counter is `mutable`
        std::cout << "Foo const" << std::endl;
    }

    int GetInvocations() const
    {
        return counter;
    }
};

int main(void)
{
    MyClass cc;
    const MyClass& ccc = cc;
    cc.Foo();
    ccc.Foo();
    std::cout << "Foo has been invoked " << ccc.GetInvocations() << " times" << std::endl;
}

ซึ่งจะส่งออก

Foo
Foo const
Foo has been invoked 2 times

187

const หมายถึงวิธีการที่สัญญาจะไม่เปลี่ยนแปลงสมาชิกของคลาสใด ๆ คุณสามารถดำเนินการสมาชิกของวัตถุที่มีการทำเครื่องหมายดังนั้นแม้ว่าวัตถุนั้นจะถูกทำเครื่องหมายconst:

const foobar fb;
fb.foo();

จะถูกกฎหมาย

ดูจำนวนและการใช้งานของ "const" ใน C ++ คืออะไร? สำหรับข้อมูลเพิ่มเติม.


47

คัดเลือกหมายความว่าวิธีการที่สามารถเรียกได้ว่ามูลค่าใดconstfoobarความแตกต่างเกิดขึ้นเมื่อคุณพิจารณาการเรียกใช้วิธีที่ไม่ใช่ const บนวัตถุ const พิจารณาว่าfoobarประเภทของคุณมีการประกาศวิธีพิเศษต่อไปนี้หรือไม่:

class foobar {
  ...
  const char* bar();
}

วิธีbar()นี้ไม่ใช่แบบคงที่และสามารถเข้าถึงได้จากค่าที่ไม่ใช่แบบคงที่เท่านั้น

void func1(const foobar& fb1, foobar& fb2) {
  const char* v1 = fb1.bar();  // won't compile
  const char* v2 = fb2.bar();  // works
}

แนวคิดเบื้องหลังconstคือการทำเครื่องหมายวิธีซึ่งจะไม่เปลี่ยนแปลงสถานะภายในของคลาส นี่เป็นแนวคิดที่ทรงพลัง แต่ไม่สามารถบังคับใช้ได้จริงใน C ++ มันสัญญามากกว่าการรับประกัน และอีกอันหนึ่งที่มักจะแตกและหักง่าย

foobar& fbNonConst = const_cast<foobar&>(fb1);

3
ฉันคิดว่าคำตอบนั้นเกี่ยวกับวิธี const อื่น ๆ และไม่เกี่ยวกับวัตถุ const
Mykola Golubyev

ขอบคุณสำหรับ "แนวคิดเบื้องหลังconstคือการทำเครื่องหมายวิธีซึ่งจะไม่เปลี่ยนสถานะภายในของคลาส" นั่นคือสิ่งที่ฉันกำลังมองหา
kovac

1
@JaredPar นี้หมายความว่าฟังก์ชันสมาชิกใดที่แสดงถึงการดำเนินการแบบอ่านอย่างเดียวควรทำเครื่องหมายเป็นconst?
kovac

26

const เหล่านี้หมายความว่าคอมไพเลอร์จะเกิดข้อผิดพลาดหากเมธอด 'with const' เปลี่ยนข้อมูลภายใน

class A
{
public:
    A():member_()
    {
    }

    int hashGetter() const
    {
        state_ = 1;
        return member_;
    }
    int goodGetter() const
    {
        return member_;
    }
    int getter() const
    {
        //member_ = 2; // error
        return member_;
    }
    int badGetter()
    {
        return member_;
    }
private:
    mutable int state_;
    int member_;
};

การทดสอบ

int main()
{
    const A a1;
    a1.badGetter(); // doesn't work
    a1.goodGetter(); // works
    a1.hashGetter(); // works

    A a2;
    a2.badGetter(); // works
    a2.goodGetter(); // works
    a2.hashGetter(); // works
}

อ่านสิ่งนี้สำหรับข้อมูลเพิ่มเติม


1
คำถามเกี่ยวกับconstฟังก์ชั่นสมาชิกที่ไม่ได้กล่าวถึงการเปลี่ยนแปลงที่ไม่สมบูรณ์ที่ดีที่สุด
IIsspectable

13

คำตอบของแบลร์อยู่ที่เครื่องหมาย

อย่างไรก็ตามโปรดทราบว่ามีmutablequalifier ซึ่งอาจถูกเพิ่มลงในสมาชิกข้อมูลของคลาส สมาชิกที่ทำเครื่องหมายดังนั้นสามารถแก้ไขได้ในconstวิธีการโดยไม่ละเมิดconstสัญญา

คุณอาจต้องการใช้สิ่งนี้ (ตัวอย่าง) หากคุณต้องการให้วัตถุจำได้ว่ามีวิธีการเฉพาะเจาะจงกี่ครั้งที่เรียกว่าในขณะที่ไม่ส่งผลกระทบต่อความ "ตรรกะ" ของวิธีการนั้น


10

ความหมายของฟังก์ชั่นสมาชิก ConstในC ++ ความรู้ทั่วไป: การเขียนโปรแกรมระดับกลางที่จำเป็นให้คำอธิบายที่ชัดเจน:

ชนิดของตัวชี้นี้ในฟังก์ชันที่ไม่ใช่สมาชิก const ของคลาส X คือ X * const นั่นคือมันเป็นตัวชี้ค่าคงที่ไปยัง X ที่ไม่คงที่ (ดูตัวชี้ Const และตัวชี้ไปที่ Const [7, 21]) เนื่องจากวัตถุที่การอ้างอิงนี้ไม่ได้เป็น const จึงสามารถแก้ไขได้ ประเภทของสิ่งนี้ในฟังก์ชั่นสมาชิก const ของคลาส X คือ const X * const นั่นคือมันเป็นตัวชี้ค่าคงที่ไปยังค่าคงที่ X เนื่องจากวัตถุที่อ้างอิงนี้คือ const จึงไม่สามารถแก้ไขได้ นั่นคือความแตกต่างระหว่างฟังก์ชั่นสมาชิก const และไม่ใช่สมาชิก

ดังนั้นในรหัสของคุณ:

class foobar
{
  public:
     operator int () const;
     const char* foo() const;
};

คุณสามารถคิดได้ดังนี้:

class foobar
{
  public:
     operator int (const foobar * const this) const;
     const char* foo(const foobar * const this) const;
};

thisconstไม่ใช่ สาเหตุที่ไม่สามารถแก้ไขได้ก็เพราะมันเป็นสิ่งที่มีค่า
ไบรอัน

7

เมื่อคุณใช้constในลายเซ็นเมธอด (เช่นที่คุณพูด:) const char* foo() const;คุณกำลังบอกคอมไพเลอร์ว่าหน่วยความจำที่ชี้ไปโดยthisวิธีนี้ไม่สามารถเปลี่ยนแปลงได้ (ซึ่งอยู่fooที่นี่)


6

ฉันต้องการเพิ่มจุดต่อไปนี้

คุณยังสามารถทำ มันconst &และconst &&

ดังนั้น,

struct s{
    void val1() const {
     // *this is const here. Hence this function cannot modify any member of *this
    }
    void val2() const & {
    // *this is const& here
    }
    void val3() const && {
    // The object calling this function should be const rvalue only.
    }
    void val4() && {
    // The object calling this function should be rvalue reference only.
    }

};

int main(){
  s a;
  a.val1(); //okay
  a.val2(); //okay
  // a.val3() not okay, a is not rvalue will be okay if called like
  std::move(a).val3(); // okay, move makes it a rvalue
}

อย่าลังเลที่จะปรับปรุงคำตอบ ฉันไม่มีความเชี่ยวชาญ


1
*thisจะเป็น lvalue เสมอแม้ว่าฟังก์ชันสมาชิกจะเป็น rvalue-ref-qualified และถูกเรียกใช้ใน rvalue ตัวอย่าง
HolyBlackCat

1
ใช่ดังนั้นฉันควรปรับปรุงคำตอบปัจจุบันของฉันอย่างไร
coder3101

ฉันหมายถึงสิ่งที่จะเขียนในความคิดเห็นในบล็อกที่ปรับพฤติกรรม
coder3101

Updated ไม่เป็นไร
coder3101

2

constคำหลักที่ใช้กับระบุการประกาศฟังก์ชันว่ามันเป็นฟังก์ชั่นสมาชิก constและมันจะไม่สามารถที่จะเปลี่ยนข้อมูลสมาชิกของวัตถุ


1

https://isocpp.org/wiki/faq/const-correctness#const-member-fns

" constฟังก์ชั่นสมาชิก" คืออะไร?

ฟังก์ชั่นสมาชิกที่ตรวจสอบ (แทนที่จะกลายพันธุ์) วัตถุ

constฟังก์ชันสมาชิกจะแสดงเป็นconstคำต่อท้ายหลังจากที่รายการพารามิเตอร์ฟังก์ชั่นของสมาชิก ฟังก์ชันสมาชิกที่มีconstคำต่อท้ายเรียกว่า "ฟังก์ชันสมาชิก const" หรือ "ผู้ตรวจสอบ" ฟังก์ชันสมาชิกที่ไม่มีconstคำต่อท้ายเรียกว่า "ฟังก์ชันที่ไม่ใช่สมาชิก const" หรือ "mutators"

class Fred {
public:
  void inspect() const;   // This member promises NOT to change *this
  void mutate();          // This member function might change *this
};
void userCode(Fred& changeable, const Fred& unchangeable)
{
  changeable.inspect();   // Okay: doesn't change a changeable object
  changeable.mutate();    // Okay: changes a changeable object
  unchangeable.inspect(); // Okay: doesn't change an unchangeable object
  unchangeable.mutate();  // ERROR: attempt to change unchangeable object
}

ความพยายามในการโทรunchangeable.mutate()เป็นข้อผิดพลาดที่เกิดขึ้นในเวลารวบรวม ไม่มีพื้นที่ว่างสำหรับรันไทม์หรือปรับโทษความเร็วconstและคุณไม่จำเป็นต้องเขียนกรณีทดสอบเพื่อตรวจสอบที่รันไทม์

ต่อท้ายconstในinspect()ฟังก์ชันสมาชิกควรจะใช้เพื่อหมายถึงวิธีการที่จะไม่เปลี่ยนแปลงของวัตถุนามธรรม (ลูกค้ามองเห็นได้) รัฐ ซึ่งแตกต่างจากการบอกว่าวิธีการจะไม่เปลี่ยน "บิตดิบ" ของโครงสร้างของวัตถุ คอมไพเลอร์ C ++ ไม่ได้รับอนุญาตให้ใช้การตีความแบบ "bitwise" นอกเสียจากว่าพวกเขาจะสามารถแก้ปัญหานามแฝงได้ซึ่งโดยทั่วไปจะไม่สามารถแก้ไขได้ ข้อมูลเชิงลึกอื่น (สำคัญ) จากปัญหานามแฝงนี้: การชี้ไปที่วัตถุที่มีตัวชี้ไปยัง const ไม่รับประกันว่าวัตถุจะไม่เปลี่ยนแปลง เป็นเพียงสัญญาว่าวัตถุจะไม่เปลี่ยนแปลงผ่านตัวชี้นั้น

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