Sign in to follow this  

Cast overloading? How does it work?

This topic is 4139 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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?

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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 int
Result: 10

Press any key to continue

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
Quote:
Original post by blarn
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?


The compiler will ALWAYS be confused when there is no direct exact match for the function it is trying to perform, and their are more than 1 implicit cast matches that can be found.

For instance if you ONLY have a sqrt function that takes a double, then calling sqrt(1) will work perfectly, it will cast the int to a double automatically. The same would be true if you have a sqrt function taking a float. But if you have (like the standard library) overloaded sqrt functions, one which takes and returns a float, and one which takes and returns a double - then the compiler will only be able to automatically resolve the situation in 3 cases: 1) when it is called with a double, 2) when it is called with a float, 3) when it is called with a type which has an implicit conversion to either float or double, but not both. The return type does not and can not enter into it. Here's an example:


// assume these 2 functions
float sqrt(float val);
double sqrt(double val);
// assume these variables are in scope and initialized
int i1, i2;
float f1, f2;
double d1, d2;

i1 = sqrt(i2); // ERROR: cannot find matching sqrt()
d1 = sqrt(i2); // ERROR: cannot find matching sqrt() - return assignment to double DOES NOT HELP lookup.
i1 = sqrt(static_cast<double>(i2)); // sqrt(double) used, warning or error on return value possible loss of precision
d1 = sqrt(static_cast<double>(i2)); // sqrt(double) used, works.
i1 = static_cast<int>(sqrt(static_cast<double>(i2))); // sqrt(double) used, works.
d1 = sqrt(f2); // sqrt(float) used, result cast to double, works.

Share this post


Link to post
Share on other sites
Okay, so as long as I define all of the appropriate operators to prevent ambiguities, would it be safe to implement a cast operator? Or are there other caveats I must consider?

Just in case it matters, I'm trying to write a fixed-point number class, and I want to allow conversions to primitive types. I'm pretty sure that there is already a fixed-point class written out there that works, but I want to write my own for practice.

Share this post


Link to post
Share on other sites

This topic is 4139 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this