C++ Overloading Conversion Operators
Solution 1
The function signature does not match the function definition.
operator unsigned long int () const;
and
CustomizedInt::operator unsigned long() { ... }
^^^
const missing
In this case you should mark the conversion operator as const
since it doesn't affect the internal state of the object.
Also, use constructor initialization lists to initialize your member variables.
CustomizedInt::CustomizedInt()
: data()
{
}
CustomizedInt::CustomizedInt(int input)
: data(input)
{
}
Solution 2
You could remove the const
from the declaration, but what you almost certainly want to do is add it to the definition:
CustomizedInt::operator unsigned long() const
{
unsigned long int output;
output = (unsigned long int)data;
return output;
}
Solution 3
Yes, if your member function doesn't affect the logical state of the object, then you should indeed postfix it with const
, so that the compiler will enforce that.
But in that case, you also need to add const
when you define the function body!
Solution 4
You just need to copy the same function prototype into the implementation. ie.
CustomizedInt::operator unsigned long int() const
Mihai Todor
Software Engineer at your service. You can find me on: Linkedin GitHub Twitter Stack Overflow tools that I created: Top N users for tag located in city / country (for answers) Top N users for tag located in city / country (for questions)
Updated on July 09, 2022Comments
-
Mihai Todor almost 2 years
I am trying to have a class that allows implicit casting to certain built in types, like unsigned long int and since I'm trying to do this as correct as possible (this is my first important project in C++), I have hit a strange issue regarding const correctness:
This works:
#include <iostream> class CustomizedInt { private: int data; public: CustomizedInt(); CustomizedInt(int input); operator unsigned long int () const { unsigned long int output; output = (unsigned long int)data; return output; } }; CustomizedInt::CustomizedInt() { this->data = 0; } CustomizedInt::CustomizedInt(int input) { this->data = input; } int main() { CustomizedInt x; unsigned long int y = x; std::cout << y << std::endl; return 0; }
But this:
#include <iostream> class CustomizedInt { private: int data; public: CustomizedInt(); CustomizedInt(int input); operator unsigned long int () const; }; CustomizedInt::CustomizedInt() { this->data = 0; } CustomizedInt::CustomizedInt(int input) { this->data = input; } CustomizedInt::operator unsigned long() { unsigned long int output; output = (unsigned long int)data; return output; } int main() { CustomizedInt x; unsigned long int y = x; std::cout << y << std::endl; return 0; }
gives me this error in Visual Studio 2010:
error C2511: 'CustomizedInt::operator unsigned long(void)' : overloaded member function not found in 'CustomizedInt'
Now, if I remove the keyword const from the operator definition, everything is OK. Is this a bug? I read that I'm supposed to use the const keyword after each (public) method / operator in order to clearly state that it does not alter the current object in any way.
Also, I know that defining such an operator may be poor practice, but I am not sure I fully understand the associated caveats. Could somebody please outline them? Would it be better practice to just define a public method called ToUnsignedLongInt?
-
Mihai Todor almost 12 yearsWell, but what if the implementation of this operator is bigger than my simple example? I don't want to add 10 lines of implementation code in the header, so I want to implement it outside of the class...
-
Mihai Todor almost 12 yearsYes, thank you! For some reason, I thought that I don't need to repeat the postpended const in the implementation... Regarding the constructors, yes, initialization lists are useful, but, in my real implementation, data has a complex type, and the constructor implementation is a bit too complex for initialization lists...
-
Jerry Coffin almost 12 years@michael85: Leave the header as it is. Just add the
const
where you implement it. The two signatures need to match. -
Praetorian almost 12 years@MihaiTodor If
data
has a complex type I'd say that's all the more reason to use an initialization list instead of assignment. The C++ FAQ explains why it is good practice and lists a few exceptions to this rule too. -
Mihai Todor almost 12 yearsWell, I completely agree, but what do you do if you need to call certain functions to initialize that data? I am using the GMP library and data is of type mpz_t, which needs to be initialized with mpz_init(...). How can I call the mpz_init function on data in the initialization list?
-
Praetorian almost 12 years@MihaiTodor In that case you can't; that's the price we pay for working with C libraries :-)
-
Mihai Todor almost 12 yearsYes, agreed :) Anyway, after I finish this project, I hope I will feel much more comfortable with C++, since my background is mostly oriented on scripting languages and C#, so I'm taking it slowly.