The programmer can stipulate how the compiler will perform implicit type conversion for classes by defining conversion constructors and functions.. // double -> Euro // int -> Euro your
Trang 1S O L U T I O N S 439
// -// Fract_t.cpp
// Testing the class Fraction
// Modules: Fract_t.cpp Fraction.cpp
//
-#include "Fraction.h"
int main()
{
Fraction a(1,3), b(4);
cout << "\nSome test results:\n\n";
cout << " a = " << a << endl;
cout << " b = " << b << endl;
cout << " a + b = " << (a + b) << endl;
cout << " a - b = " << (a - b) << endl;
cout << " a * b = " << (a * b) << endl;
cout << " a / b = " << (a / b) << endl;
cout << " a = " << a << endl;
cout << " ++a = " << ++a << endl;
a += Fraction(1,2);
cout << " a+= 1/2; a = " << a << endl;
a -= Fraction(1,2);
cout << " a-= 1/2; a = " << a << endl;
cout << "-b = " << -b << endl;
cout << "\nAnd now an input\n";
cin >> a;
cout << "\nYour input: " << a << endl;
return 0;
}
Trang 2This page intentionally left blank
Trang 34 4 1
Type Conversion for
Classes
Implicit type conversion occurs in C++ when an expression cannot be compiled directly but can be compiled after applying a conversion rule The programmer can stipulate how the compiler will perform implicit type conversion for classes by defining conversion constructors and functions.
Finally, we discuss ambiguity occurring due to type conversion and how to avoid it.
Trang 4442 C H A P T E R 2 0 T Y P E C O N V E R S I O N F O R C L A S S E S
Current Class
Another Type
Converting Constructor
Converting-Function
// The class Euro defined in the last chapter // contains the following conversion constructors:
Euro::Euro( int ); // int -> Euro
Euro::Euro( double ); // double -> Euro // The following declarations are now possible:
// Conversion constructors Euro my(100), // int-> Euro,
your(321.41); // double -> Euro
// double -> Euro
// int -> Euro
your = Euro(999.99); // Explicit conversion
// (constructor style)
my = (Euro)123.45; // Explicit conversion
// (cast style) your = my; // No conversion
When the copy constructor performs a type conversion, a temporary object is first created and this object is used in the assignment The temporary object is cleaned up later
✓ NOTE
Possible conversions
Trang 5C O N V E R S I O N C O N S T R U C T O R S 443
䊐 Possible Type Conversions
Implicit and explicit type conversion is also performed for classes in C++ As a program-mer, you decide what kind of conversion is permissible You can allow type conversion between different classes or between classes and fundamental types
Any type conversion involving a class is defined either
■ by a conversion constructor or
■ by a conversion function.
A conversion constructor performs type conversion by converting any given type to the type of the current class A conversion function performs conversion in the opposite direction, that is, it converts an object of the current class to another type—a standard type, for example
䊐 Conversion Constructors
A constructor with a single parameter determines how to form an object of the new class
from the argument passed to it For this reason, a constructor with only one parameter is
referred to as a conversion constructor The copy constructor is an exception to this rule: it
creates an object of the same class and does not perform type conversion
Each conversion constructor is placed by the compiler on a list of possible conver-sions The standard string class contains a constructor that creates a stringobject from a C string, for example
This allows you to supply a C string as an argument wherever a string object is required
䊐 Calling a Conversion Constructor
Conversion constructors have already been used in several examples; for example, in the Euroclass The compiler uses them to perform implicit and explicit type conversion
salary += (Euro)897.1; // explicit
salary += 897.1; // implicit
The last statement initially causes a type mismatch Addition is not defined for a euro and a doublevalue The compiler therefore activates the conversion constructor to cre-ate a temporary Eurotype object from the doublevalue This object is then added to the value of the salaryobject
Trang 6444 C H A P T E R 2 0 T Y P E C O N V E R S I O N F O R C L A S S E S
// Euro.h : The class Euro represents a euro
// -//
class Euro
{ private:
long data; // Euros * 100 + Cents public:
Euro( int euro = 0, int cents = 0);
Euro( double x);
// For conversion from Euro to double:
operator double() const { return (double)data/100.0; }
// other methods as before
};
// Euro_t.cpp : Testing conversions of class Euro
//
-#include "Euro.h" // Definition of the class
#include <iostream>
using namespace std;
int main() {
cout << " * * * Testing Conversions * * * \n" << endl; Euro salary( 8888,80);
double x(0.0);
salary += 1000; // implicit int -> Euro
salary += 0.10; // implicit double -> Euro
x = (double)salary; // explicit Euro -> double
x = salary.operator double(); // also possible!
// Constructor style is also safe for built-in types:
x = double(salary);
int i = salary; // Euro -> double -> int
// Output: cout << " salary = " << salary << endl; // 9888,90 Euro cout << " x = " << x << endl; // 9888.9
cout << " i = " << i << endl; // 9888 return 0;
}
Testing conversions
Trang 7C O N V E R S I O N F U N C T I O N S 445
If you need to convert an object of the current class to another type, you must define a
conversion function to do so This is an operator function that defines how conversion is
performed Conversion functions are also automatically used by the compiler to perform implicit and explicit type conversion
䊐 Defining Conversion Functions
A conversion function is always implemented as a method of the current class Its name
is made up of the operatorkeyword and the target type to convert to
The previous statement declares a conversion function where the target type is int You may have noticed that the declaration of a conversion function does not contain a return type This is because the return type is implicitly defined by the target type in the name
of the conversion function The target type can contain multiple keywords, such as
Thus, conversion functions must be written to construct a target type object from the current object,*this, and return the target object
TheEuroshown opposite contains a conversion function with a doubletarget type
In other words, the function converts a Eurotype object to a floating-point number
䊐 Conversion Function versus Conversion Constructor
The target type of a conversion function can also be a class In this case, you must decide whether it is preferable to use a conversion constructor in the target class
If you do not want to modify the target class—perhaps because it is a standard class—
a conversion function will perform the task well
䊐 Standard Type Conversion
In addition to user-definable type conversions, the compiler also performs standard type conversions In the previous example, an intvariable is assigned to a euro object by this method
This first converts a Euroobject to doubleand then to int, that is, the cents are trun-cated
Trang 8446 C H A P T E R 2 0 T Y P E C O N V E R S I O N F O R C L A S S E S
// Euro.h : The class Euro represents a euro
// -//
class Euro
{ private:
long data; // Euros * 100 + Cents public:
explicit Euro( int euro = 0, int cents = 0);
explicit Euro( double x);
// Converting Euro to double:
double asDouble() const { return (double)data/100.0;}
// No conversion function operator double(), // or as previously seen
};
// Euro_E_t.cpp // Tests explicit conversion of class Euro
//
-#include "Euro_Ex.h" // Class definition
#include <iostream>
using namespace std;
int main() {
Euro salary( 8888.8); // double constructor double x(0.0);
/* Now impossible:
salary += 1000; // implicit int -> Euro salary += 0.10; // implicit double -> Euro salary = 7777.77;
x = salary; // implicit Euro -> double
x = (double)salary; // There is no method
// operator double()
// The following conversions are ok:
salary = Euro( 7777.77); // explicit double -> Euro
salary += Euro(1000.10);
x = salary.asDouble(); // explicit by method
// Euro -> double int i = salary.asDouble(); // Euro -> double -> int return 0;
}
Testing explicit conversions
Trang 9A M B I G U I T I E S O F T Y P E C O N V E R S I O N S 447
䊐 Type Conversion Failure
Defining a conversion function or conversion constructor can prevent you from compil-ing a program that is otherwise unchanged
TheEuroclass contains a conversion constructor that converts a doublevalue to euros This means that the following statement is valid for two objects, wholesaleand retail,of the Eurotype
If you now additionally implement the conversion function
operator double()
that converts a euro to a doublevalue, the previous statement can no longer be com-piled Since both conversion types double -> Euro andEuro -> double are defined, two possible conversions could be performed:
prov2 + Euro(546.9) // To add euros
and
double(prov2) + 546.9; // To add values
// of type double However, the compiler can only perform implicit type conversion if the technique is not ambiguous If more than one choice is available, the compiler issues an error message
䊐 Avoiding Implicit Type Conversion
You can prevent ambiguities by stating any desired conversions explicitly This also has the advantage of highlighting type conversions in your source code Moreover, undesir-able type conversion, which can occur when classes are extended at a later date, can be avoided
In order to ensure that some kinds of type conversion are only performed explicitly, you can use the following techniques:
■ you can use an explicitdeclaration for the conversion constructor As the example on the opposite page shows, only explicit calls to the constructor are possible in this case
■ implicit type conversions by conversion functions can be prevented by not defin-ing the function, of course Instead you can use a method of an appropriate name, for example asType() Type conversion can only be performed by calling this function explicitly
Trang 10448 C H A P T E R 2 0 T Y P E C O N V E R S I O N F O R C L A S S E S
// Fraction.cpp //
// To simplify fractions:
void Fraction::simplify()
{ // Divide the numerator and denominator by // the greatest common divisor
if( numerator == 0) {
denominator = 1;
return;
} // Calculating the greatest common divisor // using an algorithm by Euclid
long a = (numerator < 0) ? -numerator : numerator,
b = denominator, help;
while( b != 0) {
help = a % b; a = b; b = help;
} // a is the greatest common divisor numerator /= a;
denominator /= a;
}