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:

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.

Related information