Ý nghĩa của các const
tuyên bố như thế này là gì? Những điều const
làm tôi bối rối.
class foobar
{
public:
operator int () const;
const char* foo() const;
};
Ý nghĩa của các const
tuyên bố như thế này là gì? Những điều const
làm tôi bối rối.
class foobar
{
public:
operator int () const;
const char* foo() const;
};
Câu trả lời:
Khi bạn thêm const
từ khóa vào một phương thức, this
con trỏ về cơ bản sẽ trở thành một con trỏ tới const
đối tượng và do đó bạn không thể thay đổi bất kỳ dữ liệu thành viên nào. (Trừ khi bạn sử dụng mutable
, nhiều hơn về điều đó sau).
Các const
từ khóa là một phần của chữ ký chức năng có nghĩa là bạn có thể thực hiện hai phương pháp tương tự, một trong đó được gọi khi đối tượng là const
, và một trong đó không phải là.
#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();
}
Điều này sẽ xuất
Foo
Foo const
Trong phương thức non-const, bạn có thể thay đổi các thành viên thể hiện, điều mà bạn không thể làm trong const
phiên bản. Nếu bạn thay đổi khai báo phương thức trong ví dụ trên thành mã bên dưới, bạn sẽ gặp một số lỗi.
void Foo()
{
counter++; //this works
std::cout << "Foo" << std::endl;
}
void Foo() const
{
counter++; //this will not compile
std::cout << "Foo const" << std::endl;
}
Điều này không hoàn toàn đúng, bởi vì bạn có thể đánh dấu một thành viên là mutable
và một const
phương thức có thể thay đổi nó. Nó chủ yếu được sử dụng cho các quầy nội bộ và công cụ. Giải pháp cho điều đó sẽ là đoạn mã dưới đây.
#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;
}
cái nào sẽ xuất
Foo
Foo const
Foo has been invoked 2 times
Các const có nghĩa là phương thức hứa hẹn sẽ không thay đổi bất kỳ thành viên nào trong lớp. Bạn có thể thực thi các thành viên của đối tượng được đánh dấu, ngay cả khi chính đối tượng được đánh dấu const
:
const foobar fb;
fb.foo();
sẽ là hợp pháp.
Xem có bao nhiêu và cách sử dụng của con const const trong C ++? để biết thêm thông tin.
Vòng const
loại có nghĩa là các phương thức có thể được gọi trên bất kỳ giá trị nào của foobar
. Sự khác biệt xuất hiện khi bạn xem xét việc gọi một phương thức không const trên một đối tượng const. Xem xét nếu foobar
loại của bạn có khai báo phương thức bổ sung sau:
class foobar {
...
const char* bar();
}
Phương thức bar()
này không phải là const và chỉ có thể được truy cập từ các giá trị không phải là const.
void func1(const foobar& fb1, foobar& fb2) {
const char* v1 = fb1.bar(); // won't compile
const char* v2 = fb2.bar(); // works
}
Ý tưởng đằng sau const
là đánh dấu các phương thức sẽ không làm thay đổi trạng thái bên trong của lớp. Đây là một khái niệm mạnh mẽ nhưng không thực sự có hiệu lực trong C ++. Đó là một lời hứa nhiều hơn là một sự đảm bảo. Và một trong đó thường bị hỏng và dễ dàng bị phá vỡ.
foobar& fbNonConst = const_cast<foobar&>(fb1);
const
là đánh dấu các phương thức sẽ không làm thay đổi trạng thái bên trong của lớp". Đó thực sự là những gì tôi đang tìm kiếm.
const
?
Các const này có nghĩa là trình biên dịch sẽ Lỗi nếu phương thức 'với const' thay đổi dữ liệu nội bộ.
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_;
};
Các bài kiểm tra
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
}
Đọc này để biết thêm thông tin
const
chức năng thành viên không đề cập đến khả năng thay đổi là không đầy đủ.
Câu trả lời của Blair là trên nhãn hiệu.
Tuy nhiên, lưu ý rằng có một mutable
vòng loại có thể được thêm vào các thành viên dữ liệu của một lớp. Bất kỳ thành viên nào được đánh dấu có thể được sửa đổi trong một const
phương thức mà không vi phạm const
hợp đồng.
Bạn có thể muốn sử dụng điều này (ví dụ) nếu bạn muốn một đối tượng nhớ bao nhiêu lần một phương thức cụ thể được gọi, trong khi không ảnh hưởng đến hằng số "logic" của phương thức đó.
Ý nghĩa của hàm thành viên Const trong C ++ Kiến thức chung: Lập trình trung gian thiết yếu đưa ra lời giải thích rõ ràng:
Loại của con trỏ này trong hàm không phải là thành viên của lớp X là X * const. Đó là, nó là một con trỏ không đổi đến X không đổi (xem Con trỏ và Con trỏ đến Const [7, 21]). Bởi vì đối tượng mà tham chiếu này không phải là const, nên nó có thể được sửa đổi. Kiểu này trong hàm const thành viên của lớp X là const X * const. Đó là, nó là một con trỏ không đổi đến một hằng số X. Bởi vì đối tượng mà tham chiếu này là const, nó không thể được sửa đổi. Đó là sự khác biệt giữa các hàm const và non-const.
Vì vậy, trong mã của bạn:
class foobar
{
public:
operator int () const;
const char* foo() const;
};
Bạn có thể nghĩ nó như thế này:
class foobar
{
public:
operator int (const foobar * const this) const;
const char* foo(const foobar * const this) const;
};
this
không phải là const
. Lý do tại sao nó không thể được sửa đổi là vì nó là một giá trị.
khi bạn sử dụng const
trong chữ ký phương thức (như bạn đã nói const char* foo() const;
:) bạn đang nói với trình biên dịch rằng bộ nhớ được trỏ bởi this
không thể thay đổi bằng phương thức này ( foo
ở đây).
Tôi muốn thêm điểm sau.
Bạn cũng có thể làm cho nó một const &
vàconst &&
Vì thế,
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
}
Hãy cải thiện câu trả lời. Tôi không phải là chuyên gia
*this
luôn luôn là một giá trị, ngay cả khi hàm thành viên là rvalue-ref đủ điều kiện và được gọi là một giá trị. Ví dụ .
Các const khóa được sử dụng với các quy định cụ thể chức năng khai báo rằng nó là một hàm thành viên const và nó sẽ không thể thay đổi các thành viên dữ liệu của đối tượng.
https://isocpp.org/wiki/faq/const-c Corrness # const-member-fns
"
const
Chức năng thành viên" là gì?Một chức năng thành viên kiểm tra (chứ không phải đột biến) đối tượng của nó.
Hàm
const
thành viên được biểu thị bằngconst
hậu tố ngay sau danh sách tham số của hàm thành viên. Các chức năng thành viên cóconst
hậu tố được gọi là các chức năng thành viên của const const Các hàm thành viên không cóconst
hậu tố được gọi là các hàm thành viên không phải là constclass 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 }
Nỗ lực gọi
unchangeable.mutate()
là một lỗi bắt gặp tại thời điểm biên dịch. Không có không gian thời gian chạy hoặc hình phạt tốc độ choconst
và bạn không cần phải viết các trường hợp thử nghiệm để kiểm tra nó trong thời gian chạy.Dấu vết
const
trêninspect()
hàm thành viên nên được sử dụng để có nghĩa là phương thức sẽ không thay đổi trạng thái trừu tượng (hiển thị của máy khách) của đối tượng . Điều đó hơi khác so với việc nói rằng phương thức này sẽ không thay đổi các bit thô của Google. Cấu trúc của đối tượng. Các trình biên dịch C ++ không được phép thực hiện giải thích bit bit bit, trừ khi chúng có thể giải quyết vấn đề răng cưa, điều mà thông thường không thể giải quyết được (ví dụ, một bí danh không phải là có thể tồn tại có thể thay đổi trạng thái của đối tượng). Một cái nhìn sâu sắc (quan trọng) khác về vấn đề răng cưa này: chỉ vào một đối tượng bằng con trỏ-const-const không đảm bảo rằng đối tượng sẽ không thay đổi; nó chỉ hứa hẹn rằng đối tượng sẽ không thay đổi thông qua con trỏ đó .