0% found this document useful (0 votes)
113 views

User-Defined Conversions (C++ Only)

User-defined conversions allow objects to be implicitly converted to other types using constructors or conversion functions. There are two types of user-defined conversions: conversion by constructor and conversion functions. The compiler can only use one user-defined conversion when implicitly converting a single value.

Uploaded by

arjunmajumdar
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
113 views

User-Defined Conversions (C++ Only)

User-defined conversions allow objects to be implicitly converted to other types using constructors or conversion functions. There are two types of user-defined conversions: conversion by constructor and conversion functions. The compiler can only use one user-defined conversion when implicitly converting a single value.

Uploaded by

arjunmajumdar
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 7

User-defined conversions (C++ only)

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 x; public: operator int() { return x; }; }; class B { A y; public: operator A() { return y; }; }; int main () { B b_obj; // int i = b_obj; int j = A(b_obj); }

The compiler would not allow the statement int i = b_obj. The compiler would have to implicitly convert b_obj into an object of type A (with B::operator A()), then implicitly convert that object to an integer (with A::operator int()). The statement int j = A(b_obj) explicitly converts b_obj into an object of type A, then implicitly converts that object to an integer. User-defined conversions must be unambiguous, or they are not called. A conversion function in a derived class does not hide another conversion function in a base class unless both conversion functions convert to the same type. Function overload resolution selects the most appropriate conversion function. 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.

Copy constructors (C++ only)


The copy constructor lets you create a new object from an existing one by initialization. A copy constructor of a class A is a non-template constructor in which the first parameter is of type A&, const A&, volatile A&, or const volatile A&, and the rest of its parameters (if there are any) have default values. If you do not declare a copy constructor for a class A, the compiler will implicitly declare one for you, which will be an inline public member. The following example demonstrates implicitly defined and user-defined copy constructors:
#include <iostream> using namespace std; struct A { int i; A() : i(10) { } }; struct B { int j; B() : j(20) {

cout << "Constructor B(), j = " << j << endl; } B(B& arg) : j(arg.j) { cout << "Copy constructor B(B&), j = " << j << endl; } B(const B&, int val = 30) : j(val) { cout << "Copy constructor B(const B&, int), j = " << j << endl; } }; struct C { C() { } C(C&) { } }; int main() { A a; A a1(a); B b; const B b_const; B b1(b); B b2(b_const); const C c_const; // C c1(c_const); }

The following is the output of the above example:


Constructor B(), Constructor B(), Copy constructor Copy constructor j = 20 j = 20 B(B&), j = 20 B(const B&, int), j = 30

The statement A a1(a) creates a new object from a with an implicitly defined copy constructor. The statement B b1(b) creates a new object from b with the user-defined copy constructor B::B(B&). The statement B b2(b_const) creates a new object with the copy constructor B::B(const B&, int). The compiler would not allow the statement C c1(c_const) because a copy constructor that takes as its first parameter an object of type const C& has not been defined. The implicitly declared copy constructor of a class A will have the form A::A(const A&) if the following are true: The direct and virtual bases of A have copy constructors whose first parameters have been qualified with const or const volatile The nonstatic class type or array of class type data members of A have copy constructors whose first parameters have been qualified with const or const volatile If the above are not true for a class A, the compiler will implicitly declare a copy constructor with the form A::A(A&). The compiler cannot allow a program in which the compiler must implicitly define a copy constructor for a class A and one or more of the following are true: Class A has a nonstatic data member of a type which has an inaccessible or ambiguous copy constructor. Class A is derived from a class which has an inaccessible or ambiguous copy constructor.

The compiler will implicitly define an implicitly declared constructor of a class A if you initialize an object of type A or an object derived from class A. An implicitly defined copy constructor will copy the bases and members of an object in the same order that a constructor would initialize the bases and members of the object.

Copy assignment operators (C++ only)


The copy assignment operator lets you create a new object from an existing one by initialization. A copy assignment operator of a class A is a nonstatic non-template member function that has one of the following forms: A::operator=(A) A::operator=(A&) A::operator=(const A&) A::operator=(volatile A&) A::operator=(const volatile A&)

If you do not declare a copy assignment operator for a class A, the compiler will implicitly declare one for you which will be inline public. The following example demonstrates implicitly defined and user-defined copy assignment operators:
#include <iostream> using namespace std; struct A { A& operator=(const A&) { cout << "A::operator=(const A&)" << endl; return *this; } A& operator=(A&) { cout << "A::operator=(A&)" << endl; return *this; } }; class B { A a; }; struct C { C& operator=(C&) { cout << "C::operator=(C&)" << endl; return *this; } C() { } }; int main() { B x, y; x = y; A w, z; w = z;

C i; const C j(); // i = j; }

The following is the output of the above example:


A::operator=(const A&) A::operator=(A&)

The assignment x = y calls the implicitly defined copy assignment operator of B, which calls the user-defined copy assignment operator A::operator=(const A&). The assignment w = z calls the user-defined operator A::operator=(A&). The compiler will not allow the assignment i = j because an operator C::operator=(const C&) has not been defined. The implicitly declared copy assignment operator of a class A will have the form A& A::operator=(const A&) if the following are true: A direct or virtual base B of class A has a copy assignment operator whose parameter is of type const B&, const volatile B&, or B. A non-static class type data member of type X that belongs to class A has a copy constructor whose parameter is of type const X&, const volatile X&, or X. If the above are not true for a class A, the compiler will implicitly declare a copy assignment operator with the form A& A::operator=(A&). The implicitly declared copy assignment operator returns a reference to the operator's argument. The copy assignment operator of a derived class hides the copy assignment operator of its base class. The compiler cannot allow a program in which the compiler must implicitly define a copy assignment operator for a class A and one or more of the following are true: Class A has a nonstatic data member of a const type or a reference type Class A has a nonstatic data member of a type which has an inaccessible copy assignment operator Class A is derived from a base class with an inaccessible copy assignment operator. An implicitly defined copy assignment operator of a class A will first assign the direct base classes of A in the order that they appear in the definition of A. Next, the implicitly defined copy assignment operator will assign the nonstatic data members of A in the order of their declaration in the definition of A.

Templates (C++ only)


A template describes a set of related classes or set of related functions in which a list of parameters in the declaration describe how the members of the set vary. The compiler generates new classes or functions when you supply arguments for these parameters; this process is called template instantiation, and is described in detail in Template instantiation (C++ only). This class or function definition generated from a template and a set of template parameters is called a specialization, as described in Template specialization (C++ only).
Template declaration syntax >>-+--------+---------------------------------------------------> '-export-'

>--template--<--template_parameter_list-->--declaration--------><

The compiler accepts and silently ignores the export keyword on a template. The template_parameter_list is a comma-separated list of template parameters, which are described in Template parameters (C++ only). The declaration is one of the following:: a declaration or definition of a function or a class a definition of a member function or a member class of a class template a definition of a static data member of a class template a definition of a static data member of a class nested within a class template a definition of a member template of a class or class template

The identifier of a type is defined to be a type_name in the scope of the template declaration. A template declaration can appear as a namespace scope or class scope declaration. The following example demonstrates the use of a class template:
template<class T> class Key { T k; T* kptr; int length; public: Key(T); // ... };

Suppose the following declarations appear later:


Key<int> i; Key<char*> c; Key<mytype> m;

The compiler would create three instances of class Key. The following table shows the definitions of these three class instances if they were written out in source form as regular classes, not as templates: class Key<int> i;
class Key { int k; int * kptr; int length; public: Key(int); // ... };

class Key<char*> c;
class Key { char* k; char** kptr; int length; public: Key(char*); // ... };

class Key<mytype> m;
class Key { mytype k; mytype* kptr; int length; public: Key(mytype); // ... };

Note that these three classes have different names. The arguments contained within the angle braces are not just the arguments to the class names, but part of the class names themselves. Key<int> and Key<char*> are class names. http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=

%2Fcom.ibm.xlcpp8a.doc%2Flanguage%2Fref%2Fcplr385.htm

You might also like