การconst
ประกาศเช่นนี้มีความหมายอะไร? const
สับสนฉัน
class foobar
{
public:
operator int () const;
const char* foo() const;
};
การconst
ประกาศเช่นนี้มีความหมายอะไร? const
สับสนฉัน
class foobar
{
public:
operator int () const;
const char* foo() const;
};
คำตอบ:
เมื่อคุณเพิ่ม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
const หมายถึงวิธีการที่สัญญาจะไม่เปลี่ยนแปลงสมาชิกของคลาสใด ๆ คุณสามารถดำเนินการสมาชิกของวัตถุที่มีการทำเครื่องหมายดังนั้นแม้ว่าวัตถุนั้นจะถูกทำเครื่องหมายconst
:
const foobar fb;
fb.foo();
จะถูกกฎหมาย
ดูจำนวนและการใช้งานของ "const" ใน C ++ คืออะไร? สำหรับข้อมูลเพิ่มเติม.
คัดเลือกหมายความว่าวิธีการที่สามารถเรียกได้ว่ามูลค่าใดconst
ๆ foobar
ความแตกต่างเกิดขึ้นเมื่อคุณพิจารณาการเรียกใช้วิธีที่ไม่ใช่ 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);
const
คือการทำเครื่องหมายวิธีซึ่งจะไม่เปลี่ยนสถานะภายในของคลาส" นั่นคือสิ่งที่ฉันกำลังมองหา
const
?
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
}
อ่านสิ่งนี้สำหรับข้อมูลเพิ่มเติม
const
ฟังก์ชั่นสมาชิกที่ไม่ได้กล่าวถึงการเปลี่ยนแปลงที่ไม่สมบูรณ์ที่ดีที่สุด
คำตอบของแบลร์อยู่ที่เครื่องหมาย
อย่างไรก็ตามโปรดทราบว่ามีmutable
qualifier ซึ่งอาจถูกเพิ่มลงในสมาชิกข้อมูลของคลาส สมาชิกที่ทำเครื่องหมายดังนั้นสามารถแก้ไขได้ในconst
วิธีการโดยไม่ละเมิดconst
สัญญา
คุณอาจต้องการใช้สิ่งนี้ (ตัวอย่าง) หากคุณต้องการให้วัตถุจำได้ว่ามีวิธีการเฉพาะเจาะจงกี่ครั้งที่เรียกว่าในขณะที่ไม่ส่งผลกระทบต่อความ "ตรรกะ" ของวิธีการนั้น
ความหมายของฟังก์ชั่นสมาชิก 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;
};
this
const
ไม่ใช่ สาเหตุที่ไม่สามารถแก้ไขได้ก็เพราะมันเป็นสิ่งที่มีค่า
เมื่อคุณใช้const
ในลายเซ็นเมธอด (เช่นที่คุณพูด:) const char* foo() const;
คุณกำลังบอกคอมไพเลอร์ว่าหน่วยความจำที่ชี้ไปโดยthis
วิธีนี้ไม่สามารถเปลี่ยนแปลงได้ (ซึ่งอยู่foo
ที่นี่)
ฉันต้องการเพิ่มจุดต่อไปนี้
คุณยังสามารถทำ มัน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
}
อย่าลังเลที่จะปรับปรุงคำตอบ ฉันไม่มีความเชี่ยวชาญ
*this
จะเป็น lvalue เสมอแม้ว่าฟังก์ชันสมาชิกจะเป็น rvalue-ref-qualified และถูกเรียกใช้ใน rvalue ตัวอย่าง
constคำหลักที่ใช้กับระบุการประกาศฟังก์ชันว่ามันเป็นฟังก์ชั่นสมาชิก constและมันจะไม่สามารถที่จะเปลี่ยนข้อมูลสมาชิกของวัตถุ
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 ไม่รับประกันว่าวัตถุจะไม่เปลี่ยนแปลง เป็นเพียงสัญญาว่าวัตถุจะไม่เปลี่ยนแปลงผ่านตัวชี้นั้น