Со страницы MSDN относительно константные функции
Код:
// constant_member_function.cpp
class Date
{
public:
Date( int mn, int dy, int yr );
int getMonth() const; // A read-only function
void setMonth( int mn ); // A write function; can't be const
private:
int month;
};
int Date::getMonth() const
{
return month; // Doesn't modify anything
}
void Date::setMonth( int mn )
{
month = mn; // Modifies data member
}
int main()
{
Date MyDate( 7, 4, 1998 );
const Date BirthDate( 1, 18, 1953 );
MyDate.setMonth( 4 ); // Okay
BirthDate.getMonth(); // Okay
BirthDate.setMonth( 4 ); // C2662 Error
}
Но как month
измениться в setMonth
функционировать? Функция проходит по значению и ничего не возвращает. Кроме того, как функция узнает о переменной месяца, чтобы изменить ее без передачи?
Кроме того, как функция узнает о переменной месяца, чтобы изменить ее без передачи?
Функции-члены (лайк setMonth()
) неявно получить this
указатель на объект типа (в данном случае) Date
они вызваны на. Для функций-членов, квалифицированных как const
, this
указатель является указателем на const
, что не позволит вам изменить состояние указанного объекта.
На самом деле следующее:
void Date::setMonth( int mn )
{
month = mn; // Modifies data member
}
Это эквивалентно следующему:
void Date::setMonth( int mn )
{
this->month = mn; // Modifies data member
// ^^^^^^
// "this" is a pointer to an object of type Date (i.e. Date*),
// and that is the object on which setMonth() is invoked
}
Та же история для всех других функций-членов, поэтому:
int Date::getMonth() const
{
return month; // Doesn't modify anything
}
Эквивалентно:
int Date::getMonth() const
// ^^^^^ Means the implicit "this" pointer is const
{
return this->month; // Doesn't modify anything
// ^^^^^^
// Here, "this" is a pointer to a CONST Date object (i.e. Date const*),
// and that is the object on which getMonth() is invoked
}
ВАЖНЫЙ: Неявный this
указатель на самом деле указатель на const
если объект, для которого вызывается функция-член, имеет const
квалифицированный тип.
Вот почему вы не можете вызвать функцию-член, которая не является самой const
-квалифицированный на объекте, чей тип является const
-qualified: состояние const
объект никогда не должен быть изменен, и неconst
Функция не обещает никогда ее не изменять.
Следовательно, компилятор не позволит вам вызыватьconst
функция (например, Date::setMonth()
) на объекте const
квалифицированный тип (например, const Date
) подняв ошибку.
setMonth является методом-членом класса Date и, следовательно, может видеть все переменные-члены класса Date
void Date::setMonth( int mn )
{
month = mn; // Modifies data member
}
Миннесота передается в качестве аргумента. Таким образом, все, что вы указали в качестве аргумента, будет присвоено переменной-члену месяца класса.
setMonth
является функцией-членом. Следовательно, он имеет неявное this
указатель на объект, над которым он работает. То есть каждая из переменных-членов конкретного объекта находится в области видимости, и (неконстантные) функции-члены могут изменять их.
Может быть понятнее переписать setMonth
,
void Date::setMonth( int mn )
{
this->month = mn; // Modifies data member
}
Ответ в том, что const
объявленная функция говорит, что функция не будет изменять объект, для которого вызывается функция. То есть, если вы делаете:
BirthDate.getMonth();
Это нормально, потому что пока BirthDate
это const Date
, getMonth
объявлен const
и, таким образом, гарантирует, что это не изменит его.
Причина, по которой это не работает:
BirthDate.setMonth( 4 );
в том, что setMonth
не объявлено const
Это означает, что он не оставляет никаких гарантий, что он не изменится. BirthDate
объект, к которому он относится.
Изменяются не входные параметры, а объект, для которого вызывается функция. В случае setMonth
, это month
переменная в вашем Date
экземпляр, который модифицируется.
Относительно того, как программа знает, что функция будет изменять объект: это не так. Но вы не можете вызвать функцию, которая не объявлена const
на объекте, который const
, Кроме того, пытаясь изменить (неmutable
) переменная-член в объявленной функции const
выдаст вам ошибки компилятора. Следовательно, компилятор гарантирует, что вы не нарушите свое обещание. (Хотя, естественно, существуют злые, соответствующие стандартам, способы скрытно нарушать это обещание. Но это просто аморально и опасно.)
Определяя ваш объект как const
вы заверяете компилятор, что состояние объекта не изменится. Он остается в состоянии, как будто он был создан.
При вызове вашего метода setMonth()
Вы изменяете состояние объекта, независимо от того, передаете ли вы по ссылке или по значению.
void Date::setMonth( int mn )
{
month = mn; // Modifies data member <--- Trying to modify the whole object by changing a part of it
}
MyDate
является объектом Date
учебный класс.
каждый Date
объект имеет свой int month
который известен, так как он объявлен. (Даже вне класса вы знаете, что Date
содержит int month
но вы не можете получить к нему доступ, так как это личное.
Вы также можете использовать this
указатель (который является указателем, доступным в каждом классе, указывающим на его собственную область памяти).
Код setMonth неявно делает следующее:
void Date::setMonth( int mn )
{
(*this).month = mn; // Modifies data member
}