const (Constant) Objects and const Member Functions
来源:互联网 发布:男发型设计软件 编辑:程序博客网 时间:2024/05/19 23:17
We have emphasized the principle of least privilege as one of the most fundamental principles of good software engineering. Let us see how this principle applies to objects.
Some objects need to be modifiable and some do not. The programmer may use keyword const to specify that an object is not modifiable and that any attempt to modify the object should result in a compilation error. The statement
const Time noon( 12, 0, 0 );
declares a const object noon of class Time and initializes it to 12 noon.
Software Engineering Observation 10.1
Declaring an object as consthelps enforce the principle of least privilege. Attempts to modify the object are caught at compile time rather than causing execution-time errors. Usingconst properly is crucial to proper class design, program design and coding.
Performance Tip 10.1
Declaring variables and objects const can improve performancetoday's sophisticated optimizing compilers can perform certain optimizations on constants that cannot be performed on variables.
C++ compilers disallow member function calls for const objects unless the member functions themselves are also declaredconst. This is true even for get member functions that do not modify the object. In addition, the compiler does not allow member functions declaredconst to modify the object.
A function is specified as const both in its prototype (Fig. 10.1; lines 1924) and in its definition (Fig. 10.2; lines 47, 53, 59 and 65) by inserting the keywordconst after the function's parameter list and, in the case of the function definition, before the left brace that begins the function body.
Figure 10.1. Time class definition withconst member functions.(This item is displayed on page 526 in the print version)
1 // Fig. 10.1: Time.h 2 // Definition of class Time. 3 // Member functions defined in Time.cpp. 4 #ifndef TIME_H 5 #define TIME_H 6 7 class Time 8 { 9 public:10 Time( int = 0, int = 0, int = 0 ); // default constructor1112 // set functions13 void setTime( int, int, int ); // set time14 void setHour( int ); // set hour15 void setMinute( int ); // set minute16 void setSecond( int ); // set second1718 // get functions (normally declared const)19 int getHour() const; // return hour 20 int getMinute() const; // return minute 21 int getSecond() const; // return second 2223 // print functions (normally declared const) 24 void printUniversal() const; // print universal time25 void printStandard(); // print standard time (should be const)26 private:27 int hour; // 0 - 23 (24-hour clock format)28 int minute; // 0 - 5929 int second; // 0 - 5930 }; // end class Time3132 #endif
Figure 10.2. Time class member-function definitions, includingconst member functions.(This item is displayed on pages 527 - 528 in the print version)
1 // Fig. 10.2: Time.cpp 2 // Member-function definitions for class Time. 3 #include <iostream> 4 using std::cout; 5 6 #include <iomanip> 7 using std::setfill; 8 using std::setw; 910 #include "Time.h" // include definition of class Time1112 // constructor function to initialize private data;13 // calls member function setTime to set variables;14 // default values are 0 (see class definition)15 Time::Time( int hour, int minute, int second )16 {17 setTime( hour, minute, second );18 } // end Time constructor1920 // set hour, minute and second values21 void Time::setTime( int hour, int minute, int second )22 {23 setHour( hour );24 setMinute( minute );25 setSecond( second );26 } // end function setTime2728 // set hour value29 void Time::setHour( int h )30 {31 hour = ( h >= 0 && h < 24 ) ? h : 0; // validate hour32 } // end function setHour3334 // set minute value35 void Time::setMinute( int m )36 {37 minute = ( m >= 0 && m < 60 ) ? m : 0; // validate minute38 } // end function setMinute3940 // set second value41 void Time::setSecond( int s )42 {43 second = ( s >= 0 && s < 60 ) ? s : 0; // validate second44 } // end function setSecond4546 // return hour value47 int Time::getHour() const // get functions should be const48 {49 return hour;50 } // end function getHour5152 // return minute value53 int Time::getMinute() const54 {55 return minute;56 } // end function getMinute5758 // return second value59 int Time::getSecond() const60 {61 return second;62 } // end function getSecond6364 // print Time in universal-time format (HH:MM:SS)65 void Time::printUniversal() const66 {67 cout << setfill( '0' ) << setw( 2 ) << hour << ":"68 << setw( 2 ) << minute << ":" << setw( 2 ) << second;69 } // end function printUniversal7071 // print Time in standard-time format (HH:MM:SS AM or PM)72 void Time::printStandard() // note lack of const declaration73 {74 cout << ( ( hour == 0 || hour == 12 ) ? 12 : hour % 12 )75 << ":" << setfill( '0' ) << setw( 2 ) << minute76 << ":" << setw( 2 ) << second << ( hour < 12 ? " AM" : " PM" );77 } // end function printStandard
Common Programming Error 10.1
Defining as const a member function that modifies a data member of an object is a compilation error.
Common Programming Error 10.2
Defining as const a member function that calls a non-const member function of the class on the same instance of the class is a compilation error.
Common Programming Error 10.3
Invoking a non-const member function on aconst object is a compilation error.
Software Engineering Observation 10.2
A const member function can be overloaded with a non-const version. The compiler chooses which overloaded member function to use based on the object on which the function is invoked. If the object is const, the compiler uses the const version. If the object is notconst, the compiler uses the non-const version.
An interesting problem arises for constructors and destructors, each of which typically modifies objects. Theconst declaration is not allowed for constructors and destructors. A constructor must be allowed to modify an object so that the object can be initialized properly. A destructor must be able to perform its termination housekeeping chores before an object's memory is reclaimed by the system.
Common Programming Error 10.4
Attempting to declare a constructor or destructor const is a compilation error.
Defining and Using const Member Functions
The program of Figs. 10.110.3 modifies classTime of Figs. 9.99.10 by making itsget functions and printUniversal functionconst. In the header file Time.h (Fig. 10.1), lines 1921 and 24 now include keywordconst after each function's parameter list. The corresponding definition of each function inFig. 10.2 (lines 47, 53, 59 and 65, respectively) also specifies keywordconst after each function's parameter list.
Figure 10.3 instantiates twoTime objectsnon-const object wakeUp (line 7) and const objectnoon (line 8). The program attempts to invoke non-const member functionssetHour (line 13) and printStandard (line 20) on the const objectnoon. In each case, the compiler generates an error message. The program also illustrates the three other member-function-call combinations on objectsa non-const member function on a non-const object (line 11), a const member function on a non-const object (line 15) and a const member function on aconst object (lines 1718). The error messages generated for non-const member functions called on aconst object are shown in the output window. Notice that, although some current compilers issue only warning messages for lines 13 and 20 (thus allowing this program to be executed), we consider these warnings to be errorsthe ANSI/ISO C++ standard disallows the invocation of a non-const member function on a const object.
Figure 10.3. const objects andconst member functions.(This item is displayed on pages 528 - 529 in the print version)
1 // Fig. 10.3: fig10_03.cpp 2 // Attempting to access a const object with non-const member functions. 3 #include "Time.h" // include Time class definition 4 5 int main() 6 { 7 Time wakeUp( 6, 45, 0 ); // non-constant object 8 const Time noon( 12, 0, 0 ); // constant object 910 // OBJECT MEMBER FUNCTION11 wakeUp.setHour( 18 ); // non-const non-const1213 noon.setHour( 12 ); // const non-const1415 wakeUp.getHour(); // non-const const1617 noon.getMinute(); // const const18 noon.printUniversal(); // const const1920 noon.printStandard(); // const non-const21 return 0;22 } // end main
Borland C++ command-line compiler error messages:
Warning W8037 fig10_03.cpp 13: Non-const function Time::setHour(int) called for const object in function main() Warning W8037 fig10_03.cpp 20: Non-const function Time::printStandard() called for const object in function main()
Microsoft Visual C++.NET compiler error messages:
C:\cpphtp5_examples\ch10\Fig10_01_03\fig10_03.cpp(13) : error C2662: 'Time::setHour' : cannot convert 'this' pointer from 'const Time' to 'Time &' Conversion loses qualifiers C:\cpphtp5_examples\ch10\Fig10_01_03\fig10_03.cpp(20) : error C2662: 'Time::printStandard' : cannot convert 'this' pointer from 'const Time' to 'Time &' Conversion loses qualifiers
GNU C++ compiler error messages:
fig10_03.cpp:13: error: passing `const Time' as `this' argument of `void Time::setHour(int)' discards qualifiers fig10_03.cpp:20: error: passing `const Time' as `this' argument of `void Time::printStandard()' discards qualifiers
Notice that even though a constructor must be a non-const member function (Fig. 10.2, lines 1518), it can still be used to initialize a const object (Fig. 10.3, line 8). The definition of theTime constructor (Fig. 10.2, lines 1518) shows that theTime constructor calls another non-const member functionsetTime (lines 2126)to perform the initialization of aTime object. Invoking a non-const member function from the constructor call as part of the initialization of aconst object is allowed. The "const ness" of a const object is enforced from the time the constructor completes initialization of the object until that object's destructor is called.
Also notice that line 20 in Fig. 10.3 generates a compilation error even though member function printStandard of classTime does not modify the object on which it is invoked. The fact that a member function does not modify an object is not sufficient to indicate that the function is constant functionthe function must explicitly be declaredconst.
Initializing a const Data Member with a Member Initializer
The program of Figs. 10.410.6 introduces usingmember initializer syntax. All data memberscan be initialized using member initializer syntax, butconst data members and data members that are references must be initialized using member initializers. Later in this chapter, we will see that member objects must be initialized this way as well. InChapter 12 when we study inheritance, we will see that base-class portions of derived classes also must be initialized this way.
The constructor definition (Fig. 10.5, lines 1116) uses amember initializer list to initialize classIncrement's data membersnon-const integer count and const integer increment (declared in lines 1920 of Fig. 10.4). Member initializers appear between a constructor's parameter list and the left brace that begins the constructor's body. The member initializer list (Fig. 10.5, lines 1213) is separated from the parameter list with a colon (:). Each member initializer consists of the data member name followed by parentheses containing the member's initial value. In this example,count is initialized with the value of constructor parameter c andincrement is initialized with the value of constructor parameter i. Note that multiple member initializers are separated by commas. Also, note that the member initializer list executes before the body of the constructor executes.
Figure 10.4. Increment class definition containing non-const data membercount and const data member increment.(This item is displayed on page 530 in the print version)
1 // Fig. 10.4: Increment.h 2 // Definition of class Increment. 3 #ifndef INCREMENT_H 4 #define INCREMENT_H 5 6 class Increment 7 { 8 public: 9 Increment( int c = 0, int i = 1 ); // default constructor1011 // function addIncrement definition12 void addIncrement()13 {14 count += increment;15 } // end function addIncrement1617 void print() const; // prints count and increment18 private:19 int count;20 const int increment; // const data member21 }; // end class Increment2223 #endif
Figure 10.5. Member initializer used to initialize a constant of a built-in data type.(This item is displayed on page 530 in the print version)
1 // Fig. 10.5: Increment.cpp 2 // Member-function definitions for class Increment demonstrate using a 3 // member initializer to initialize a constant of a built-in data type. 4 #include <iostream> 5 using std::cout; 6 using std::endl; 7 8 #include "Increment.h" // include definition of class Increment 910 // constructor11 Increment::Increment( int c, int i )12 : count( c ), // initializer for non-const member 13 increment( i ) // required initializer for const member14 {15 // empty body16 } // end constructor Increment1718 // print count and increment values19 void Increment::print() const20 {21 cout << "count = " << count << ", increment = " << increment << endl;22 } // end function print
Figure 10.6. Invoking an Increment object'sprint and addIncrement member functions.
1 // Fig. 10.6: fig10_06.cpp 2 // Program to test class Increment. 3 #include <iostream> 4 using std::cout; 5 6 #include "Increment.h" // include definition of class Increment 7 8 int main() 9 {10 Increment value( 10, 5 );1112 cout << "Before incrementing: ";13 value.print();1415 for ( int j = 1; j <= 3; j++ )16 {17 value.addIncrement();18 cout << "After increment " << j << ": ";19 value.print();20 } // end for2122 return 0;23 } // end main
Before incrementing: count = 10, increment = 5 After increment 1: count = 15, increment = 5 After increment 2: count = 20, increment = 5 After increment 3: count = 25, increment = 5
Software Engineering Observation 10.3
A const object cannot be modified by assignment, so it must be initialized. When a data member of a class is declaredconst, a member initializer must be used to provide the constructor with the initial value of the data member for an object of the class. The same is true for references.
Erroneously Attempting to Initialize aconst Data Member with an Assignment
The program ofFigs. 10.710.9 illustrates the compilation errors caused by attempting to initializeconst data member increment with an assignment statement (Fig. 10.8, line 14) in theIncrement constructor's body rather than with a member initializer. Note that line 13 ofFig. 10.8 does not generate a compilation error, becausecount is not declared const. Also note that the compilation errors produced by Microsoft Visual C++.NET refer toint data member increment as a "const object." The ANSI/ISO C++ standard defines an "object" as any "region of storage." Like instances of classes, fundamental-type variables also occupy space in memory, so they are often referred to as "objects."
Figure 10.7. Increment class definition containing non-const data membercount and const data member increment.(This item is displayed on pages 532 - 533 in the print version)
1 // Fig. 10.7: Increment.h 2 // Definition of class Increment. 3 #ifndef INCREMENT_H 4 #define INCREMENT_H 5 6 class Increment 7 { 8 public: 9 Increment( int c = 0, int i = 1 ); // default constructor1011 // function addIncrement definition12 void addIncrement()13 {14 count += increment;15 } // end function addIncrement1617 void print() const; // prints count and increment18 private:19 int count;20 const int increment; // const data member21 }; // end class Increment2223 #endif
Figure 10.8. Erroneous attempt to initialize a constant of a built-in data type by assignment.(This item is displayed on page 533 in the print version)
1 // Fig. 10.8: Increment.cpp 2 // Attempting to initialize a constant of 3 // a built-in data type with an assignment. 4 #include <iostream> 5 using std::cout; 6 using std::endl; 7 8 #include "Increment.h" // include definition of class Increment 910 // constructor; constant member 'increment' is not initialized11 Increment::Increment( int c, int i ) 12 { 13 count = c; // allowed because count is not constant 14 increment = i; // ERROR: Cannot modify a const object 15 } // end constructor Increment 1617 // print count and increment values18 void Increment::print() const19 {20 cout << "count = " << count << ", increment = " << increment << endl;21 } // end function print
Common Programming Error 10.5
Not providing a member initializer for aconst data member is a compilation error.
Software Engineering Observation 10.4
Constant data members (const objects andconst variables) and data members declared as references must be initialized with member initializer syntax; assignments for these types of data in the constructor body are not allowed.
Note that function print (Fig. 10.8, lines 1821) is declaredconst. It might seem strange to label this function const, because a program probably will never have aconst Increment object. However, it is possible that a program will have aconst reference to an Increment object or a pointer to const that points to anIncrement object. Typically, this occurs when objects of class Increment are passed to functions or returned from functions. In these cases, only theconst member functions of class Increment can be called through the reference or pointer. Thus, it is reasonable to declare functionprint as constdoing so prevents errors in these situations where anIncrement object is treated as a const object.
Error-Prevention Tip 10.1
Declare as const all of a class's member functions that do not modify the object in which they operate. Occasionally this may seem inappropriate, because you will have no intention of creatingconst objects of that class or accessing objects of that class through const references or pointers to const. Declaring such member functionsconst does offer a benefit, though. If the member function is inadvertently written to modify the object, the compiler will issue an error message.
Figure 10.9. Program to test classIncrement generates compilation errors.(This item is displayed on pages 533 - 534 in the print version)
1 // Fig. 10.9: fig10_09.cpp 2 // Program to test class Increment. 3 #include <iostream> 4 using std::cout; 5 6 #include "Increment.h" // include definition of class Increment 7 8 int main() 9 {10 Increment value( 10, 5 );1112 cout << "Before incrementing: ";13 value.print();1415 for ( int j = 1; j <= 3; j++ )16 {17 value.addIncrement();18 cout << "After increment " << j << ": ";19 value.print();20 } // end for2122 return 0;23 } // end main
Borland C++ command-line compiler error message:
Error E2024 Increment.cpp 14: Cannot modify a const object in function Increment::Increment(int,int)
Microsoft Visual C++.NET compiler error messages:
C:\cpphtp5_examples\ch10\Fig10_07_09\Increment.cpp(12) : error C2758: 'Increment::increment' : must be initialized in constructor base/member initializer list C:\cpphtp5_examples\ch10\Fig10_07_09\Increment.h(20) : see declaration of 'Increment::increment' C:\cpphtp5_examples\ch10\Fig10_07_09\Increment.cpp(14) : error C2166: l-value specifies const object
GNU C++ compiler error messages:
Increment.cpp:12: error: uninitialized member 'Increment::increment' with 'const' type 'const int' Increment.cpp:14: error: assignment of read-only data-member `Increment::increment'
- const (Constant) Objects and const Member Functions
- const member functions and const return values
- Item16 Make const member functions thread safe
- Constant Member Functions
- Constant Member Functions
- Constant Member Functions
- Constant Member Functions
- const(constant)
- const member function不明白
- Const Member Function(C++)
- Relationship of the this pointer and (non-)const member function
- const functions 总结
- C++ primer 5th edition:7.1.2节(关于this指针;关于const member functions)
- const* and *const
- const and not const
- const的object和 const member function
- const Pointers and Pointer to const Objects 常量指针和指向常量对象的指针
- const member function can return non-const type member vars
- 不用加减乘除做加法
- mysql表类型MyISAM和InnoDB区别
- HDU 1085 Holding Bin-Laden Captive!
- ubuntu12.04 报错curses.h: No such file or directory
- 如何解决APK文件传到网站上出现不能被下载的问题
- const (Constant) Objects and const Member Functions
- Qt-对话框
- Nginx的事件驱动架构
- Android技巧之shape实现控件圆角,背景,边框等属性
- 执行sudo apt-get install 时出现E: 无法获得锁 /var/lib/dpkg/lock - open (11: 资源暂时不可用)
- hadoop在ubuntu 12.04系统上的安装
- C++ 基本类型(Primitive Type) 的(const reference type) 参数有何用处?
- linux设备驱动——输入子系统
- hdu 4902 Nice boat(树形结构-线段树)