Cast overloading? How does it work?

Started by
10 comments, last by Rainault 17 years, 8 months ago
I remember seeing in a thread a while back about a class that overloaded something I'd never seen before: operator bool. From what I gathered, it looked like it allowed you to provide a method to cast the object into a primitive type. Is that how it works? Can you also create similar overloads for user-defined types? Is there anything wrong with doing this? And is there a reason why std::string uses c_str() instead of casting into a char*? Or does this type of overloading not work for pointers?
Advertisement
You can define a conversion operator for any type. The syntax goes:
class MyClass {  public:    operator TYPE() {      // return a TYPE    }};

This creates an implicit conversion from MyClass to TYPE. However, conversion operators, like any implicit conversion can be very error prone. If std::string had an implicit const char * conversion, then this code would compile: str = str + 4; And it wouldn't do anything close to what you'd expect.
class Foo{public:   operator int()   {      // return an int somehow   }};Foo operator+(const Foo & lhs, int rhs){   // do some addition-like operation and return a Foo}Foo f;f = f + 4;


In the above example, will the operator+ defined for Foo take precedence, or will it try to convert f into an int before adding them together? In other words, if I define the appropriate operator(s) so that an implicit cast isn't necessary, will it do the cast anyway?
Did you try it?
I just tested it as I was curious too, and operator + is called.

Quick and dirty copy & paste.

// dfdf.cpp : Defines the entry point for the console application.//#include "stdafx.h"class Foo{public:    Foo (const int value) : m_value (value)    {    }    operator int()    {        printf ("operator int\n");        return m_value;    }    int m_value;};Foo operator+(const Foo & lhs, int rhs){    printf ("operator +\n");    return Foo (lhs.m_value + rhs);}int _tmain(int argc, _TCHAR* argv[]){    Foo f (6);    f = f + 4;    printf ("Result: %d\n\n", (int) f);        return 0;}


Output:

operator +operator intResult: 10Press any key to continue
I'm not at a computer with a compiler at the moment, but I'll be sure to try it when I get home. I guess I was wondering if the result could vary between compilers. My natural assumption would be that the implicit cast wouldn't be done if an appropriate operator has already been defined, but I'll give it a shot when I get the chance.
No, it shouldn't vary from compiler to compiler (modulo compiler bugs anyways).
which gets called is based on order-of-operations, not compiler.

X = Y + Z

the rules of C++ say that this will be the same as X = ( Y + Z ) ... so it will be evaluated as first an attempt to do operator + WITH NO KNOWLEDGE that it will later be assigned into X - the lookup will not ever change from being the same as having jut done

Y + Z; // all by itself and throwing away the result.

Then given whatever the function it found to do the + with, it will then have that return type. Now it will look for a way to do: X = (result) ... based on the return type, having absolutely no concept of what types Y and Z we're at all.

At any stage in this process, casting might occur if no natural match is found and if an implicit cast / constructor is found which meets with the normal rules of C++ implicit casting.
I think sometimes the compiler complains because it's ambiguous? I don't know when it does which, buut for the example how does the compiler know whether to convert 'f' to an int and then do an integer addition, or apply f's operator+ and then convert the result to an int.

.. err so if the compiler can apply f's operator+ without a conversion, it will apply it, but if the types weren't quite right, then it'd try to cast f to an int and do integer addition?
Consider this example:
#include	<iostream>class A {public:	A(int x) : m_x(x) {}	~A() {}	operator double() // (1)	{		std::cout << "A::operator double()" << std::endl;		return m_x;	}	operator int() // (2)	{		std::cout << "A::operator int()" << std::endl;		return m_x;	}	A operator +(int d) // (3)	{		std::cout << "A::operator +(int)" << std::endl;		return A(m_x+d);	}private:	int m_x;};int main (){	A a(1);	A b = a + 2; // (4)	double c = b + 1.5; // (5)	return 0;}

As you can see - there is operator+(int) defined (3), therefor compiler will use this operator for the line (4). However, when compiling line (5) - compiler will issue an error because there is actualy three options that compiler can do and none of them are perfect (because there is no operator+(double)). And those options for the compiler are:
1) cast 1.5 to int and perform operator+(A, int);
2) cast A to int and perform operator+(int, double);
3) cast A to double and perform operator+(double, double).

Compiler can not decide what to do. Easy fix would be to add the cast to the code manualy:
// Original://	double c = b + 1.5; // (5)// 1) cast 1.5 to int and perform operator+(A, int);	double c1 = b + static_cast<int>(1.5);// 2) cast A to int and perform operator+(int, double);	double c2 = static_cast<int>(b) + 1.5;// 3) cast A to double and perform operator+(double, double).	double c3 = static_cast<double>(b) + 1.5;

Now, because of the explicit casts - compiler knows exactly what to do in each case, so there will be no compile errors.

This topic is closed to new replies.

Advertisement