const objects
We can create const objects using declarations such as
const DayOfYear jan1st( 1, 1);
The DayOfYear object jan1st is not modifiable by any member or
non-member function. Any attempt to modify this object (i.e. calling a mutator) such as
jan1st.Set(1, 2); results in a compiler error like this
myfile.cpp: In function `int main()':
myfile.cpp:20: passing `const DayOfYear' as `this' argument of `void
DayOfYear::Set(int, int)' discards qualifiers
The phrase "discards qualifiers" is your hint that there is some violation
of the const rules. We'll discuss "this" later
Temporary objects created by the compiler are const objects.
const member functions
The purpose of some member functions is to modify the object (e.g. mutators)
for which they are called.
Other member functions (e.g. accessors) do not modify the object.
How can the compiler tell the difference? Does it make a difference?
As we saw above under the const object section
above it clearly makes a difference.
The code jan1st.Set(1, 2); causes a compiler error because
Set( ); is a mutator. How does the compiler know that?
The code jan1st.Output( ); should be allowed since the
Output( ) function doesn't (or at least shouldn't) change the object on which it was called.
How does the compiler know? You have to tell it.
Adding the keyword const to the end of a member function's prototype
tells the compiler:
I promise not to modify the object which calls me (directly or indirectly),
and therefore I may be called by const objects.
"Directly" means changes a private data member in the body
of the code.
"Indirectly" means call a non-const member function or pass
the const object as a non-const paramter.
We're now ready for the final version of the DayOfYear class.
class DayOfYear
{
public:
// constructors
DayOfYear ( int initialMonth = 1, int initialDay = 1 );
// accessors
int GetMonthNumber ( ) const;
int GetDay( ) const;
// mutators
void Set( int newMonth, int newDay );
void Set( int newMonth );
// services
void Input( );
void Output( ) const;
private:
int m_month;
int m_day;
};
Rules of Engagement -- Objects, Functions and Parameters
- const member functions may be invoked for const and non-const objects.
- non-const member functions can only be invoked for non-const objects.
If a non-const member function is invoked on a const object, it is a compiler error.
- non-const objects may be used for const and non-const parameters
- const objects may only be used for const parameters
- const methods cannot invoke non-const methods
A short example
#include
#include "DayOfYear.h"
using namespace std;
// a function that inputs a DayOfYear
// from the user
void InputDayOfYear( DayOfYear& doy)
{
cout << "Please input the day of year: \n";
doy.Input( )
}
// a function that prints a DayOfYear
// to the standard output
void OutputDayOfYear( const DayOfYear& doy)
{
cout << "The day of year is \n";
doy.Output( );
}
int main ( )
{
// a const object
// must be initialized; cannot be changed
const DayOfYear jan1st( 1, 1 );
// an object that is not constant
// aka a "non-const" object
DayOfYear today;
// since non-const objects are changeable
// they can be passed as const or non-const params
// with no problems
InputDayOfYear ( today );
OutputDayOfYear( today );
// similarly, all class methods may be called for
// a non-const object
today.GetMonthNumber ( ); // const method
today.GetDay( ) // const method
today.Set( 10, 5); // non-const method
today.Set( 12 ); // non-const method
today.Input( ); // non-const method
today.Output() // const method
// since const objects are not changeable
// they may not be passed as non-const parameters
InputDayOfYear ( jan1st ); // **** compiler error ***
// but may be passed as const parameter
OutPutDayOfYear ( jan1st ); // no problem
// similarly, only const methods can be called
// for a const object, since non-const methods
// will try to change the object
jan1st.GetMonthNumber ( ); // const method -- no problem
jan1st.GetDay( ) // const method -- no problem
jan1st.Set( 10, 5); // non-const method *** compiler error
jan1st.Set( 12 ); // non-const method *** compiler error
jan1st.Input( ); // non-const method *** compiler error
jan1st.Output() // const method -- no problem
return 0;
}
A common, subtle coding error
This common mistake leads to a compiler error. Do you see why?
int DayOfYear::GetDay ( ) const
{
if (m_day < 1 )
Set( m_month, 1 );
return m_day;
}
as does this one
void Bob ( const DayOfYear& doy)
{
OutputDayOfYear ( doy );
cout << "Please enter your birth month and day \n";
int birthMonth, birthDay;
cin >> birthMonth >> birthDay;
doy.Set( birthMonth, birthDay );
}
A summary of the "Rules of Engagement"
Recall that objects are almost always passed
to functions "by reference" to avoid unnecssary
copying.