explicit Constructors

In Section 11.8 and Section 11.9, we discussed that any single-argument constructor can be used by the compiler to perform an implicit conversionthe type received by the constructor is converted to an object of the class in which the constructor is defined. The conversion is automatic and the programmer need not use a cast operator. In some situations, implicit conversions are undesirable or error-prone. For example, our Array class in Fig. 11.6 defines a constructor that takes a single int argument. The intent of this constructor is to create an Array object containing the number of elements specified by the int argument. However, this constructor can be misused by the compiler to perform an implicit conversion.

Common Programming Error 11.9

Unfortunately, the compiler might use implicit conversions in cases that you do not expect, resulting in ambiguous expressions that generate compilation errors or resulting in execution-time logic errors.


Accidentally Using a Single-Argument Constructor as a Conversion Constructor

The program (Fig. 11.16) uses the Array class of Figs. 11.611.7 to demonstrate an improper implicit conversion.

Figure 11.16. Single-argument constructors and implicit conversions.

 1 // Fig. 11.16: Fig11_16.cpp
 2 // Driver for simple class Array.
 3 #include 
 4 using std::cout;
 5 using std::endl;
 6
 7 #include "Array.h"
 8
 9 void outputArray( const Array & ); // prototype
10
11 int main()
12 {
13 Array integers1( 7 ); // 7-element array
14 outputArray( integers1 ); // output Array integers1
15 outputArray( 3 ); // convert 3 to an Array and output Array's contents
16 return 0;
17 } // end main
18
19 // print Array contents
20 void outputArray( const Array &arrayToOutput )
21 {
22 cout << "The Array received has " << arrayToOutput.getSize()
23 << " elements. The contents are:
" << arrayToOutput << endl;
24 } // end outputArray
 
 The Array received has 7 elements. The contents are:
 0 0 0 0
 0 0 0
 The Array received has 3 elements. The contents are:
 0 0 0
 

Line 13 in main instantiates Array object integers1 and calls the single argument constructor with the int value 7 to specify the number of elements in the Array. Recall from Fig. 11.7 that the Array constructor that receives an int argument initializes all the array elements to 0. Line 14 calls function outputArray (defined in lines 2024), which receives as its argument a const Array & to an Array. The function outputs the number of elements in its Array argument and the contents of the Array. In this case, the size of the Array is 7, so seven 0s are output.

Line 15 calls function outputArray with the int value 3 as an argument. However, this program does not contain a function called outputArray that takes an int argument. So, the compiler determines whether class Array provides a conversion constructor that can convert an int into an Array. Since any constructor that receives a single argument is considered to be a conversion constructor, the compiler assumes the Array constructor that receives a single int is a conversion constructor and uses it to convert the argument 3 into a temporary Array object that contains three elements. Then, the compiler passes the temporary Array object to function outputArray to output the Array's contents. Thus, even though we do not explicitly provide an outputArray function that receives an int argument, the compiler is able to compile line 15. The output shows the contents of the three-element Array containing 0s.


Preventing Accidental Use of a Single-Argument Constructor as a Conversion Constructor

C++ provides the keyword explicit to suppress implicit conversions via conversion constructors when such conversions should not be allowed. A constructor that is declared explicit cannot be used in an implicit conversion. Figure 11.17 declares an explicit constructor in class Array. The only modification to Array.h was the addition of the keyword explicit to the declaration of the single-argument constructor at line 15. No modifications are required to the source-code file containing class Array's member-function definitions.


Figure 11.17. Array class definition with explicit constructor.

(This item is displayed on page 619 in the print version)

 1 // Fig. 11.17: Array.h
 2 // Array class for storing arrays of integers.
 3 #ifndef ARRAY_H
 4 #define ARRAY_H
 5
 6 #include 
 7 using std::ostream;
 8 using std::istream;
 9
10 class Array
11 {
12 friend ostream &operator<<( ostream &, const Array & );
13 friend istream &operator>>( istream &, Array & );
14 public:
15 explicit Array( int = 10 ); // default constructor
16 Array( const Array & ); // copy constructor
17 ~Array(); // destructor
18 int getSize() const; // return size
19
20 const Array &operator=( const Array & ); // assignment operator
21 bool operator==( const Array & ) const; // equality operator
22
23 // inequality operator; returns opposite of == operator
24 bool operator!=( const Array &right ) const
25 {
26 return ! ( *this == right ); // invokes Array::operator==
27 } // end function operator!=
28
29 // subscript operator for non-const objects returns lvalue
30 int &operator[]( int );
31
32 // subscript operator for const objects returns rvalue
33 const int &operator[]( int ) const;
34 private:
35 int size; // pointer-based array size
36 int *ptr; // pointer to first element of pointer-based array
37 }; // end class Array
38
39 #endif

Figure 11.18 presents a slightly modified version of the program in Fig. 11.16. When this program is compiled, the compiler produces an error message indicating that the integer value passed to outputArray at line 15 cannot be converted to a const Array &. The compiler error message is shown in the output window. Line 16 demonstrates how the explicit constructor can be used to create a temporary Array of 3 elements and pass it to function outputArray.

Figure 11.18. Demonstrating an explicit constructor.

 1 // Fig. 11.18: Fig11_18.cpp
 2 // Driver for simple class Array.
 3 #include 
 4 using std::cout;
 5 using std::endl;
 6
 7 #include "Array.h"
 8
 9 void outputArray( const Array & ); // prototype
10
11 int main()
12 {
13 Array integers1( 7 ); // 7-element array
14 outputArray( integers1 ); // output Array integers1
15 outputArray( 3 ); // convert 3 to an Array and output Array's contents
16 outputArray( Array( 3 ) ); // explicit single-argument constructor call
17 return 0;
18 } // end main
19
20 // print array contents
21 void outputArray( const Array &arrayToOutput )
22 {
23 cout << "The Array received has " << arrayToOutput.getSize()
24 << " elements. The contents are:
" << arrayToOutput << endl;
25 } // end outputArray
 
 c:cpphtp5_examplesch11Fig11_17_18Fig11_18.cpp(15) : error C2664:
 'outputArray' : cannot convert parameter 1 from 'int' to 'const Array &'
 Reason: cannot convert from 'int' to 'const Array'
 Constructor for class 'Array' is declared 'explicit'
 

Common Programming Error 11.10

Attempting to invoke an explicit constructor for an implicit conversion is a compilation error.

Common Programming Error 11.11

Using the explicit keyword on data members or member functions other than a single-argument constructor is a compilation error.


Error-Prevention Tip 11.3

Use the explicit keyword on single-argument constructors that should not be used by the compiler to perform implicit conversions.


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



C++ How to Program
C++ How to Program (5th Edition)
ISBN: 0131857576
EAN: 2147483647
Year: 2004
Pages: 627

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net