В чем смысл 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
В методе non-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 << "The MyClass instance has been invoked " << ccc.GetInvocations() << " times" << endl;
}
который будет выводить
Foo
Foo const
The MyClass instance 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
}
Подробнее о
const
функциях-членах, которые не упоминают mutable, в лучшем случае неполон.
Ответ Блэра находится на отметке.
Однако обратите внимание, что существует спецификатор mutable
, который может быть добавлен к членам данных класса. Любой отмеченный таким образом член может быть изменен методом const
без нарушения договора const
.
Возможно, вы захотите использовать это (например), если хотите, чтобы объект запоминал, сколько раз вызывается какой-либо конкретный метод, не влияя на "логическую" константу этого метода.
Значение функции члена-члена в C++ Общие знания: основное промежуточное программирование дает четкое объяснение:
Тип этого указателя в не-const-членной функции класса X есть X * const. То есть его постоянный указатель на непостоянный X (см. Указатели указателей и указатели на константу [7, 21]). Поскольку объект, к которому это относится, не является константой, его можно изменить. Тип этого в функции-член const класса X является const X * const. То есть, это постоянный указатель на константу X. Поскольку объектом, к которому относится это, является const, его нельзя изменить. Это разница между функциями const и non-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;
};
когда вы используете const
в сигнатуре метода (например, ваш сказал: const char* foo() const;
), вы сообщаете компилятору, что память, на которую указывает this
, не может быть изменена этим методом (который foo
здесь).
Просто чтобы добавить ответ Матса Фредрикссона...
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
}
const
заключается в том, чтобы маркировать методы, которые не изменят внутреннее состояние класса». Это действительно то, что я искал.