A reference to an object is an alias for the name of the object and, hence, may be used on the left side of an assignment statement. In this context, the reference makes a perfectly acceptable lvalue that can receive a value. One way to use this capability (unfortunately!) is to have a public member function of a class return a reference to a private data member of that class. Note that if a function returns a const reference, that reference cannot be used as a modifiable lvalue.
The program of Figs. 9.149.16 uses a simplified Time class (Fig. 9.14 and Fig. 9.15) to demonstrate returning a reference to a private data member with member function badSetHour (declared in Fig. 9.14 at line 15 and defined in Fig. 9.15 at lines 2933). Such a reference return actually makes a call to member function badSetHour an alias for private data member hour! The function call can be used in any way that the private data member can be used, including as an lvalue in an assignment statement, thus enabling clients of the class to clobber the class's private data at will! Note that the same problem would occur if a pointer to the private data were to be returned by the function.
Figure 9.14. Returning a reference to a private data member.
1 // Fig. 9.14: Time.h 2 // Declaration of class Time. 3 // Member functions defined in Time.cpp 4 5 // prevent multiple inclusions of header file 6 #ifndef TIME_H 7 #define TIME_H 8 9 class Time 10 { 11 public: 12 Time( int = 0, int = 0, int = 0 ); 13 void setTime( int, int, int ); 14 int getHour(); 15 int &badSetHour( int ); // DANGEROUS reference return 16 private: 17 int hour; 18 int minute; 19 int second; 20 }; // end class Time 21 22 #endif |
Figure 9.15. Returning a reference to a private data member.
(This item is displayed on pages 504 - 505 in the print version)
1 // Fig. 9.15: Time.cpp 2 // Member-function definitions for Time class. 3 #include "Time.h" // include definition of class Time 4 5 // constructor function to initialize private data; 6 // calls member function setTime to set variables; 7 // default values are 0 (see class definition) 8 Time::Time( int hr, int min, int sec ) 9 { 10 setTime( hr, min, sec ); 11 } // end Time constructor 12 13 // set values of hour, minute and second 14 void Time::setTime( int h, int m, int s ) 15 { 16 hour = ( h >= 0 && h < 24 ) ? h : 0; // validate hour 17 minute = ( m >= 0 && m < 60 ) ? m : 0; // validate minute 18 second = ( s >= 0 && s < 60 ) ? s : 0; // validate second 19 } // end function setTime 20 21 // return hour value 22 int Time::getHour() 23 { 24 return hour; 25 } // end function getHour 26 27 // POOR PROGRAMMING PRACTICE: 28 // Returning a reference to a private data member. 29 int &Time::badSetHour( int hh ) 30 { 31 hour = ( hh >= 0 && hh < 24 ) ? hh : 0; 32 return hour; // DANGEROUS reference return 33 } // end function badSetHour |
Figure 9.16 declares Time object t (line 12) and reference hourRef (line 15), which is initialized with the reference returned by the call t.badSetHour(20). Line 17 displays the value of the alias hourRef. This shows how hourRef breaks the encapsulation of the classstatements in main should not have access to the private data of the class. Next, line 18 uses the alias to set the value of hour to 30 (an invalid value) and line 19 displays the value returned by function getHour to show that assigning a value to hourRef actually modifies the private data in the Time object t. Finally, line 23 uses the badSetHour function call itself as an lvalue and assigns 74 (another invalid value) to the reference returned by the function. Line 28 again displays the value returned by function getHour to show that assigning a value to the result of the function call in line 23 modifies the private data in the Time object t.
Figure 9.16. Returning a reference to a private data member.
(This item is displayed on pages 505 - 506 in the print version)
1 // Fig. 9.16: fig09_16.cpp 2 // Demonstrating a public member function that 3 // returns a reference to a private data member. 4 #include 5 using std::cout; 6 using std::endl; 7 8 #include "Time.h" // include definition of class Time 9 10 int main() 11 { 12 Time t; // create Time object 13 14 // initialize hourRef with the reference returned by badSetHour 15 int &hourRef = t.badSetHour( 20 ); // 20 is a valid hour 16 17 cout << "Valid hour before modification: " << hourRef; 18 hourRef = 30; // use hourRef to set invalid value in Time object t 19 cout << " Invalid hour after modification: " << t.getHour(); 20 21 // Dangerous: Function call that returns 22 // a reference can be used as an lvalue! 23 t.badSetHour( 12 ) = 74; // assign another invalid value to hour 24 25 cout << " ************************************************* " 26 << "POOR PROGRAMMING PRACTICE!!!!!!!! " 27 << "t.badSetHour( 12 ) as an lvalue, invalid hour: " 28 << t.getHour() 29 << " *************************************************" << endl; 30 return 0; 31 } // end main
|
Error-Prevention Tip 9.4
Returning a reference or a pointer to a private data member breaks the encapsulation of the class and makes the client code dependent on the representation of the class's data. So, returning pointers or references to private data is a dangerous practice that should be avoided. |
Introduction to Computers, the Internet and World Wide Web
Introduction to C++ Programming
Introduction to Classes and Objects
Control Statements: Part 1
Control Statements: Part 2
Functions and an Introduction to Recursion
Arrays and Vectors
Pointers and Pointer-Based Strings
Classes: A Deeper Look, Part 1
Classes: A Deeper Look, Part 2
Operator Overloading; String and Array Objects
Object-Oriented Programming: Inheritance
Object-Oriented Programming: Polymorphism
Templates
Stream Input/Output
Exception Handling
File Processing
Class string and String Stream Processing
Web Programming
Searching and Sorting
Data Structures
Bits, Characters, C-Strings and structs
Standard Template Library (STL)
Other Topics
Appendix A. Operator Precedence and Associativity Chart
Appendix B. ASCII Character Set
Appendix C. Fundamental Types
Appendix D. Number Systems
Appendix E. C Legacy Code Topics
Appendix F. Preprocessor
Appendix G. ATM Case Study Code
Appendix H. UML 2: Additional Diagram Types
Appendix I. C++ Internet and Web Resources
Appendix J. Introduction to XHTML
Appendix K. XHTML Special Characters
Appendix L. Using the Visual Studio .NET Debugger
Appendix M. Using the GNU C++ Debugger
Bibliography