Search

Sponsored Links

Meta

Categories

Archives

Recent Posts

RSS Feeds

04
Nov

Implicit Type Conversions - part 2

Related Blog Items

Standard Type Conversions

Many C and C++ operators cause implicit type conversions, which change the type of an expression. When you add values having different data types, both values are first converted to the same type. For example, when a short int value and an int value are added together, the
short int value is converted to the int type. It can result in loss of data if the value of the original object is outside the range representable by the shorter type.

Implicit type conversions can occur when:

* An operand is prepared for an arithmetic or logical operation.
* An assignment is made to an lvalue that has a different type than the assigned value.
* A function is provided an argument value that has a different type than the parameter.
* The value specified in the return statement of a function has a different type from the defined return type for the function.

You can perform explicit type conversions using the C-style cast, the C++ function-style cast, or one of the C++ cast operators.

#include <iostream>
using namespace std;
 
int main() {
float num = 98.76;
int x1 = (int) num;
int x2 = int(num);
int x3 = static_cast<int>(num);
 
cout < < "x1 = " << x1 << endl;
cout << "x2 = " << x2 << endl;
cout << "x3 = " << x3 << endl;
}

The following is the output of the above example:

x1 = 98
x2 = 98
x3 = 98

The integer x1 is assigned a value in which num has been explicitly converted to an int with the C-style cast. The integer x2 is assigned a value that has been converted with the function-style cast. The integer x3 is assigned a value that has been converted with the static_cast operator.

User-Defined Conversions

User-defined conversions allow you to specify object conversions with constructors or with conversion functions. User-defined conversions are implicitly used in addition to standard conversions for conversion of initializers, functions arguments, function return values, expression operands, expressions controlling iteration, selection statements, and explicit type conversions.

There are two types of user-defined conversions:

* Conversion by constructor
* Conversion functions

The compiler can use only one user-defined conversion (either a conversion constructor or a conversion function) when implicitly converting a single value. The following example demonstrates this:

class A {
int a_int;
char* a_carp;
public:
operator int() { return a_int; }
operator char*() { return a_carp; }
};
 
class B : public A {
float b_float;
char* b_carp;
public:
operator float() { return b_float; }
operator char*() { return b_carp; }
};
 
int main () {
B b_obj;
//?  long a = b_obj;
char* c_p = b_obj;
}

The compiler would not allow the statement long a = b_obj. The compiler could either use A::operator int() or B::operator float() to convert b_obj into a long. The statement char* c_p = b_obj uses B::operator char*() to convert b_obj into a char* because B::operator char*() hides A::operator char*().

When you call a constructor with an argument and you have not defined a constructor accepting that argument type, only standard conversions are used to convert the argument to another argument type acceptable to a constructor for that class. No other constructors or conversions functions are called to convert the argument to a type acceptable to a constructor defined for that class. The following example demonstrates this:

class A {
public:
A() { }
A(int) { }
};
 
int main() {
A a1 = 1.234;
//? ?  A moocow = "text string";
}

The compiler allows the statement A a1 = 1.234. The compiler uses the standard conversion of converting 1.234 into an int, then implicitly calls the converting constructor A(int). The compiler would not allow the statement A moocow = “text string”; converting a text string to an integer is not a standard conversion.

Conversion by Constructor

A converting constructor is a single-parameter constructor that is declared without the function specifier explicit. The compiler uses converting constructors to convert objects from the type of the first parameter to the type of the converting constructor’s class. The following example demonstrates this:

class Y {
int a, b;
char* name;
public:
Y(int i) { };
Y(const char* n, int j = 0) { };
};
 
void add(Y) { };
 
int main() {
 
// equivalent to
// obj1 = Y(2)
Y obj1 = 2;
 
// equivalent to
// obj2 = Y("somestring",0)
Y obj2 = "somestring";
 
// equivalent to
// obj1 = Y(10)
obj1 = 10;
 
// equivalent to
// add(Y(5))
add(5);
}

The above example has the following two converting constructors:

* Y(int i)which is used to convert integers to objects of class Y.
* Y(const char* n, int j = 0) which is used to convert pointers to strings to objects of class Y.

The compiler will not implicitly convert types as demonstrated above with constructors declared with the explicit keyword. The compiler will only use explicitly declared constructors in new expressions, the static_cast expressions and explicit casts, and the initialization of bases and members. The following example demonstrates this:

class A {
public:
explicit A() { };
explicit A(int) { };
};
 
int main() {
A z;
//?  A y = 1;
A x = A(1);
A w(1);
A* v = new A(1);
A u = (A)1;
A t = static_cast<a>(1);
}</a>

The compiler would not allow the statement A y = 1 because this is an implicit conversion; class A has no conversion constructors.

A copy constructor is a converting constructor.

Conversion Functions

C++You can define a member function of a class, called a conversion function, that converts from the type of its class to another specified type.

-[-class-::] operator–[const][volatile]–conversion_type
-{–function_body–}-

A conversion function that belongs to a class X specifies a conversion from the class type X to the type specified by the conversion_type. The following code fragment shows a conversion function called operator int():

class Y {
int b;
public:
operator int();
};
Y::operator int() {
return b;
}
void f(Y obj) {
int i = int(obj);
int j = (int)obj;
int k = i + obj;
}

All three statements in function f(Y) use the conversion function Y::operator int().

Classes, enumerations, typedef names, function types, or array types cannot be declared or defined in the conversion_type. You cannot use a conversion function to convert an object of type A to type A, to a base class of A, or to void.

Conversion functions have no arguments, and the return type is implicitly the conversion type. Conversion functions can be inherited. You can have virtual conversion functions but not static ones.

Cast Expressions

The cast operator is used for explicit type conversions. This operator has the following form, where T is a type, and expr is an expression:

( T ) expr

It converts the value of expr to the type T. In C, the result of this operation is not an lvalue. In C++, the result of this operation is an lvalue if T is a reference; in all other cases, the result is an rvalue.

C++The remainder of this section pertains to C++ only.

A cast is a valid lvalue if its operand is an lvalue. In the following simple assignment expression, the right-hand side is first converted to the specified type, then to the type of the inner left-hand side expression, and the result is stored. The value is converted back to the specified type, and becomes the value of the assignment. In the following example, i is of type char *.

(int)i = 8? ? ? ? // This is equivalent to the following expression
(int)(i = (char*) (int)(8))

For compound assignment operation applied to a cast, the arithmetic operator of the compound assignment is performed using the type resulting from the cast, and then proceeds as in the case of simple assignment. The following expressions are equivalent. Again, i is of type char *.

(int)i += 8? ? ? ? // This is equivalent to the following expression
(int)(i = (char*) (int)((int)i = 8))

Taking the address of an lvalue cast will not work because the address operator may not be applied to a bit field.

You can also use the following function-style notation to convert the value of expr to the type T. :

expr( T )

A function-style cast with no arguments, such as X() is equivalent to the declaration X t(), where t is a temporary object. Similarly, a function-style cast with more than one argument, such as X(a, b), is equivalent to the declaration X t(a, b).

For C++, the operand can have class type. If the operand has class type, it can be cast to any type for which the class has a user-defined conversion function. Casts can invoke a constructor, if the target type is a class, or they can invoke a conversion function, if the source type is a class. They can be ambiguous if both conditions hold.

An explicit type conversion can also be expressed by using the C++ type conversion operator static_cast.

Example

The following demonstrates the use of the cast operator. The example dynamically creates an integer array of size 10:

#include <stdlib .h>
 
int main(void) {
int* myArray = (int*) malloc(10 * sizeof(int));
free(myArray);
return 0;
}</stdlib>

The malloc() library function returns a void pointer that points to memory that will hold an object of the size of its argument. The statement int* myArray = (int*) malloc(10 * sizeof(int)) does the following

* Creates a void pointer that points to memory that can hold ten integers.
* Converts that void pointer into an integer pointer with the use of the cast operator.
* Assigns that integer pointer to myArray. Because a name of an array is the same as a pointer to the initial element of the array, myArray is an array of ten integers stored in the memory created by the call to malloc().

[tags]standard type conversions, user defined conversion, conversion by constructor[/tags]

Popularity: 6%

You need to log on to convert this article into PDF


Related Blog Items

No Comments

No comments yet.

Leave a comment

*
To prove you're a person (not a spam script), type the security word shown in the picture.
Anti-spam image