В чем смысл 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
. Если вы измените объявление метода в приведенном выше примере на приведенный ниже код, вы получите несколько ошибок.
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++;
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" << endl;
}
который будет выводить
Foo
Foo const
Foo has been invoked 2 times
Сопоставление означает, что метод promises не должен изменять каких-либо членов класса. Вы могли бы выполнить объекты, отмеченные таким образом, даже если сам объект был помечен const
:
const foobar fb;
fb.foo();
будет законным.
См. Сколько и какие использует "const" в С++? для получения дополнительной информации.
Квалификатор const
означает, что методы могут быть вызваны при любом значении foobar
. Разница возникает, когда вы рассматриваете вызов метода non-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
заключается в том, чтобы отметить методы, которые не изменят внутреннее состояние класса. Это мощная концепция, но на самом деле не реализуется в С++. Это скорее обещание, чем гарантия. И тот, который часто ломается и легко ломается.
foobar& fbNonConst = const_cast<foobar&>(fb1);
Эти константы означают, что компилятор будет Error, если метод '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
}
Подробнее о
Ответ Блэра находится на отметке.
Однако обратите внимание, что существует спецификатор mutable
, который может быть добавлен к членам данных класса. Любой отмеченный таким образом член может быть изменен методом const
без нарушения договора const
.
Возможно, вы захотите использовать это (например), если хотите, чтобы объект запоминал, сколько раз вызывается какой-либо конкретный метод, не влияя на "логическую" константу этого метода.
Значение функции-члена Const в C++ Общее знание: основное программирование на промежуточном уровне дает четкое объяснение:
Тип указателя this в неконстантной функции-члене класса X является X * const. То есть его постоянный указатель на непостоянный X (см. Const Указатели и Указатели на Const [7, 21]). Потому что объект к которому это относится, не является константой, его можно изменить. Тип это в const функция-член класса X является const X * const. Это является постоянным указателем на постоянную X. Поскольку объект Это относится к константам и не может быть изменено. Это Разница между константными и неконстантными функциями-членами.
Итак, в вашем коде:
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;
};
когда вы используете 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
}
Не стесняйтесь, чтобы улучшить ответ. Я не эксперт
Ключевое слово const, используемое с объявлением функции, указывает, что это постоянная функция-член, и она не сможет изменять члены-данные объекта.
Просто чтобы добавить ответ Матса Фредрикссона...
class MyClass {
static int counter; // mutable (or static) allows const method to change it
public:
void Foo() {std::cout << "Foo " << counter++ << std::endl;}
void Foo() const {std::cout << "Foo const " << counter++ << std::endl;} // const obj calls this
};
int MyClass::counter = 0; // static counter needs initializing
int main() {
MyClass a;
const MyClass& b = a;
a.Foo();
b.Foo(); // calls const version
}