C++ conversion operators - c++

I know the deal .The compiler tries to convert one object into the other objects's type with the help of conversion operator .Two ways to do this .Constructor (Converts a class to the other) or conversion operator .So , this one is just to test if I am thorough with the concepts .The code below gives the error
using namespace std ;
class A
{
int i ;
public:
A(int a=0){this->i=a;}
A operator+(const A& b){
A c ;
return c(this->i+b.i);
}
void show()
{
cout<<i<<endl;
}
};
int main()
{
A a1(1),a2(2),a3;
a3=a2+a1;
a3.show();
return 0;
}
I guess the error is in the operator + .When I try to assign A(i) .There is no match for an operator which could create an A from an int .
But Then I see this A's constructor lurking behind .It can convert an int into an A .Suppose , it does convert int into an A.Then , the call becomes A(B) .This is equivalent to the copy constructor .Hence , this call should work .But it doesn't .All in all , am pretty confused .
Please help .

In these two lines you are telling the compiler to construct an A object with the default constructor, then call its nonexistent operator () (int) and return its return value:
A c ;
return c(this->i+b.i);
Use either
A c(i + b.i);
return c;
or
return A(i + b.i);
On a side note, an example for an implicit conversion operator, for your class:
operator int () const
{
return i;
}
But their use smells like bad design, and can cause bad stuff to happen, like implicit conversion to bool or a pointer. Use something else instead, like an int toInt () const member function.

Related

overload [] operator to return a variant type

EDIT: thanks to the answers I was able to solve all the issues with my code. I post here the solution: it might be useful to somebody in the future. In particular, the suggestion of using a proxy class proved very useful! The example doens't consider all the cases but it should be trivial to add another type to the variant!
I am writing a C++ (C11 - Linux) custom class that sort of behaves like an unordered map {key, value}. I would like to overload the [] operator so that I can use the class with the same syntax as an unordered map: object[key] would return value.
The problem is that I need object[key] to return a variant type. I can store internally value as a string or struct but, when I retrieve it by using object[key], I need the returned value to be an int, float or string depending on some internal condition determined at runtime.
This is why I was thinking about using the boost::variant library ... but I am opened to any other suggestion. The only restriction is that the test class (in the example) have to compiled as a shared library .so and that the code must be C11 compatible (I mean compilable by GNU g++ 4.8.5).
I wrote a simple example to show what kind of behavior I would like The example is not meant to mean anything. It is just to illustrate the kind of error that I am getting. The real class that I am writing has a different structure but the usage of bool::variant and operator [] overload is the same.
test.cpp
#include <boost/variant.hpp>
typedef boost::variant<int, float> test_t;
class Test
{
int i ;
float f;
void set(int randomint, test_t tmp){
if ( randomint == 0 ) i = boost::get<int>(tmp);
else f = boost::get<float>(tmp);
}
test_t get(int randomint){
if ( randomint == 0 ) return i;
else return f;
}
struct IntOrFloat {
int randomint;
Test *proxy;
explicit operator int () const
{ return boost::get<int>(proxy->get(randomint)); }
void operator= (int tmp)
{ proxy->set(randomint, tmp); }
explicit operator float () const
{ return boost::get<float>(proxy->get(randomint)); }
void operator= (float tmp)
{ proxy->set(randomint, tmp); }
};
public:
IntOrFloat operator [](int randomint)
{ return IntOrFloat{randomint, this}; }
const IntOrFloat operator [](int randomint) const
{ return IntOrFloat{randomint, (Test *) this}; }
};
main.cpp
#include <iostream>
#include <boost/variant.hpp>
#include "test.cpp"
#define INTEGER 0
#define FLOAT 1
int main (void) {
Test test;
int i = 3;
float f = 3.14;
test[INTEGER] = i;
test[FLOAT] = f;
int x = (int) test[INTEGER];
float y = (float) test[FLOAT];
std::cout << x << std::endl;
std::cout << y << std::endl;
return 0;
}
To compile and run
g++ -fPIC -std=c++11 -shared -rdynamic -o test.so test.cpp
g++ -std=c++11 -o test main.cpp -Lpath/to/the/test.so -l:test.so
LD_LIBRARY_PATH="path/to/the/test.so" ./test
In C++, overload resolution does not happen on the return type, so given
int foo() { return 0; }
float foo() { return 0.f; }
there is no sanctioned way for the compiler to differentiate
int x = foo();
float f = foo();
. There is a trick using conversion operator overloads:
#include <iostream>
struct IntOrFloat {
operator int () const {
std::cout << "returning int\n";
return 0;
}
operator float () const {
std::cout << "returning float\n";
return 0.f;
}
};
IntOrFloat foo() { return IntOrFloat(); }
int main () {
int x = foo();
float f = foo();
}
You can force more verbosity by making the conversion explicit:
explicit operator int () const ...
explicit operator float () const ...
int x = static_cast<int>(foo());
int x = float(foo()); // old-style-cast
This proxy (or other conversion operator tricks) are as far as you'll to simulate return type overload resolution.
The idea once arised while searching a solution to supporting <euclidian vector> * <euclidian vector>-syntax, i.e. an operator* which either means dot product or vector product, depending on the type of the variable the product is assigned to.
In the end, it was not really practical and did not contribute positively to readability. The more verbose forms dot(vec, vec) and cross(vec, vec) were superior for several reasons, among which:
principle of least surprise: the computer graphics community is used to the terms "dot" and "cross"
less cryptic error messages: because this proxy technique is not idiomatic in C++, people are not used to the kind of error messages this temporal indirection yields
temporal and/or spatial locality: you are essentially returning a closure with code in it, which can be executed many times at many places. this can be doubly bad as it does not (actually, does) work well with auto & kind of declarations:
int main () {
const auto &f = foo();
const int g = f;
const int h = f;
std::cout << (int)f << "\n";
}
This prints something multiple times, going hand in hand with the least surprise principle. Of course this becomes less severe if your proxy basically just forwards readily available values. But the error messages won't become any better!
Note you can also incorporate template conversion operator overloads and wild metaprogramming. While worth a fun experiment, this is not something I'd love to put into a production code base, for maintenance and readability will even decrease.
What remains? Infinite possibilities; but some of the most feasible:
Variant datatypes
Tuple datatypes (look into std::tuple, which comes with conversion operators in case of distinct member types)
Different idioms (e.g. named methods instead of operator method)
Different algorithms
Different data structures
Different design patterns
When you use return i, what's happening underneath the hood is the creation of a temporary of type test_t that encapsulates that int value. This works fine in the function test::test_variant because the return type is test_t. This cannot work in the function test::operator[] because the return type is test_t&. The language prohibits creating a modifiable (l-value) reference to a temporary.
One way to make this work is to add a data member of type test_t to your class, with your test function operator[] setting this member and returning it rather than returning a temporary. Your real class will most likely do something different.

Invalid arguments when calling getter member

The error happen when I try to use one of my get function on parameter inside member functions. The error is:
Invalid arguments '. Candidates are : int getTotalArea() .
here is an example from my code :
class Apartment{
public : // ...
enum SquareType {EMPTY, WALL, NUM_SQUARE_TYPES};
bool operator<(const Apartment& apartment); // done - need help
int getTotalArea(); // done
private:
int price;
int length;
int width;
SquareType** squares;
};
int Apartment::getTotalArea()
{
int count=0;
for(int i=0;i<width;i++)
{
for(int j=0;j<length;j++)
{
if(squares[i][j]==EMPTY)
{
count++;
}
}
}
return count;
}
bool Apartment::operator<(const Apartment& apartment)
{
int thisArea=this->getTotalArea();
int paramArea=apartment.getTotalArea(); // the error line is here !!!
//the error is Invalid arguments '. Candidates are : int getTotalArea() .
double thisRatio=((double)price)/thisArea;
double paramRatio=((double)apartment.price)/paramArea;
if(thisRatio==paramRatio)
{
return price < apartment.price;
}
return thisRatio<paramRatio;
}
Have I done something wrong ?
It's the first time I'm using c++ ... by the way - any comments for the rest of the code are fine as well.
From the answer of PcAF seems you've heavily changed your initial post without modifying your question. Very bad!
However, the problem you're facing now with getTotalArea is that it isn't declared const.
See https://stackoverflow.com/a/751690/781933 for explanation.
Seems like you misunderstood operator overloading (as members)
When overloading some operator as member, then first operand of that operator is object on which member operator overload is called and second operand is parameter to that function (in case of binary operators).
operator + can be used as binary(2 operands) or unary operator(1 operand).
Here it seems like you want to overload binary version as member:
Apartment operator+(const Apartment& apartment1,const Apartment& apartment2);
but since first operand is object on which that member "function" is called it must take only 1 parameter (which is second operand).
Apartment operator+(const Apartment& apartment2);
Here is the second mistake:
Apartment& operator=(SquareType** squares, int length, int width, int price);
operator = is binary operator (2 operands), therefore if you want to overload it as member function it has to take exactly one parameter (which is second operand of =), not 4 parameters.

Array Index operator overloaded.Unable to use the comparison operator now

I overloaded array subscript ( [] ) operator. I have made it return an integer as I wont be using it for any assignment purposes. However, I am unable to use the comparison operator now!
Here is the code
class Set
{
public:
virtual int operator[](int i) = 0;
virtual int size() = 0;
void union_operation(Set* second);
void interesction_operation(Set* second);
};
void Set::union_operation(Set* second)
{
int second_size = second->size();
for(int i=0;i<second_size;i++)
{
for(int j=0;j<this->size();j++)
{
//The line below doesnt work!
if(this[j]==second[i])
{
break;
}
}
}
}
The implementation of operator overloading is carried out in a derived class.
Since the overloaded operator will return an integer, hence the comparison is between two integers, which is perfectly valid. Why does this line still give an error?
In C++, this is a pointer that requires dereferencing before you can use it. Unless you're passing it to a function of course.
So, in order for your comparison to work, it should look like the following:
if((*this)[j] == (*second)[i])
{
break;
}
EDIT: second is also a Set pointer so you must dereference it to use it too.

Syntax for Overloading Type Conversion Operator

I'm sorry if this has been asked already, but I'm still learning C++ and struggling with a bit of syntax.
I'm supposed to overload the type conversion operator, so that it will accept an object and return an int value, based on a protected int inside that object.
Header file:
definitions.h
class Baseballs
{
protected:
int currentValue;
public:
Baseballs(int);
int operator= (Baseballs&); // ??????
}
Methods:
methods.cpp
#include "definitions.h"
Baseballs::Baseballs(int value)
{
currentValue = value;
}
int Baseballs::operator=(Baseballs &obj) // ??????
{
int temp = obj.currentValue;
return temp;
}
So in main.cpp, if I create an object:
Baseballs order(500);
Then 500 is assigned to currentValue. I need to be able to assign that to an int variable, and ultimately print it for verification, such as:
int n = order;
cout << n;
What I'm having trouble with is the syntax for overloading =. Can someone tell me what the proper syntax for the definition and method should be?
The overloaded = is really to assign to objects of the same type. Ex:
order = another_order;
What you are looking for is an overloaded conversion operator.
operator int() { return currentvalue; }
However this is generally not regarded as good practice, due to unknown conversions. An explicit overload is much safer:
explicit operator int() {...}
However you would need to do:
int n = static_cast<int>(order);

Use copy constructor for "abstract" super class

I have a "abstract" super class called RealAlgebraicNumber and two inherited classes called IntervalRepresentation and NumericRepresentation. Both IntervalRepresentation and NumericRepresentation have a copy constructor and they work fine.
I use shared_ptr like this:
typedef std::tr1::shared_ptr<RealAlgebraicNumber> RealAlgebraicNumberPtr;
At another part of the programm I want to use the copy constructor for the abstract super class RealAlgeraicNumber:
RealAlgebraicPoint RealAlgebraicPoint::conjoin (const RealAlgebraicNumber& N)
{
vector<RealAlgebraicNumberPtr> v (mNumbers.begin(), mNumbers.end());
v.push_back(RealAlgebraicNumberPtr(new RealAlgebraicNumber(N)));
return RealAlgebraicPoint(v);
}
I did not define a copy constructor for RealAlgebraicNumber at all. I have no idea what it should do. The compiler is fine with the code, but unfortuantly when I test conjoin like this:
vector<RealAlgebraicNumberPtr> v;
v.push_back(RealAlgebraicNumberPtr(new NumericRepresentation(2)));
RealAlgebraicPoint PPP (v);
PPP.print();
PPP = PPP.conjoin (NumericRepresentation(3));
PPP.print();
The output is:
( 2 )( 2 null )
And print was defined like this:
void RealAlgebraicNumberFactory::print (const RealAlgebraicNumberPtr& A)
{
IntervalRepresentationPtr irA = std::tr1::dynamic_pointer_cast<IntervalRepresentation> (A);
NumericRepresentationPtr nrA = std::tr1::dynamic_pointer_cast<NumericRepresentation> (A);
if (irA != 0)
cout << irA->Interval();
else if (nrA != 0)
cout << static_cast<numeric>(*nrA);
else
cout << "null";
}
I use a loop to call the static-print function and put the representation between the ( ).
I tryed it the way Cat Plus Plus propused: virtual method in RealAlgebraicNumber,
virtual std::tr1::shared_ptr<RealAlgebraicNumber> clone();
implementation in e.g. NumericRepresentation
RealAlgebraicNumberPtr NumericRepresentation::clone()
{
return RealAlgebraicNumberPtr(new NumericRepresentation(*this));
}
And then used it like this in conjoin:
RealAlgebraicPoint RealAlgebraicPoint::conjoin (const RealAlgebraicNumber& N)
{
vector<RealAlgebraicNumberPtr> v (mNumbers.begin(), mNumbers.end());
v.push_back(RealAlgebraicNumberPtr(N.clone()));
return RealAlgebraicPoint(v);
}
Now the compiler complains:
RealAlgebraicPoint.cpp: In member function 'GiNaC::RealAlgebraicPoint GiNaC::RealAlgebraicPoint::conjoin(const GiNaC::RealAlgebraicNumber&)':
RealAlgebraicPoint.cpp:66:48: error: passing 'const GiNaC::RealAlgebraicNumber' as 'this' argument of 'virtual std::tr1::shared_ptr<GiNaC::RealAlgebraicNumber> GiNaC::RealAlgebraicNumber::clone()' discards qualifiers
I dont get it! Whats wrong?
Edit: Oke its fine! It had something to do with const, and virtual.
Thank you!
Joachim
If you didn't define a copy ctor, compiler will generate a default one, doing memberwise copy. What you probably want is polymorphic clone, to preserve the type, and call a proper copy ctor. For that, add a new virtual member, e.g. virtual RealAlgebraicNumber* clone();, and override it in every subclass to do return new T(*this); — then your conjoin will look like this:
RealAlgebraicPoint RealAlgebraicPoint::conjoin (const RealAlgebraicNumber& N)
{
vector<RealAlgebraicNumberPtr> v(mNumbers.begin(), mNumbers.end());
v.push_back(RealAlgebraicNumberPtr(N.clone()));
return RealAlgebraicPoint(v);
}