Conversion constructor between classes c++ - c++

The background: I am reading a wonderful book, where they briefly mentioned conversion constructors.
Though I understand fundamentals of the conversion constructors, I was a bit lost, when in practice problems section they asked:
Write a conversion constractor that converts ratnum into realnum from the code that I received prior to the problem:
class ratnum {
int num, denom;
public:
ratnum(int numenator = 2, int denominator = 3) : num(numenator), denom(denominator) {}
void show() { cout << static_cast<double>(num) / denom << endl; }
double result() { return num / denom; }
};
class realnum {
int number;
public:
realnum(double numr = 0) : number (numr) {}
};
I always dealt with the conversion constructors as such:
ratnum one = 10; //or
ratnum two = {10, 2}
But never saw that we can convert from class to a class type.
Could you, please, say how such conversion constructor should work (maybe with example)?
Is defining a function result of the ratnum class and writing:
realnum check = one.result();
is what is meant here?

But never saw that we can convert from class to a class type. Could
you, please, say how such conversion constructor should work (maybe
with example)?
It's exactly the same as converting from a non-class type. There's literally absolutely no difference at all.

I assume what they meant is that there is an overload of the constructor that takes an input of the other class, for example
realnum(ratnum const& other) : number{other.result()} {}
And vice-versa to construct a ratnum from a realnum, although that could be less trivial as there are irrational numbers, infinitely repeating numbers, etc.
You could use this version of the constructor to do something like
ratnum a{2, 4};
realnum b{a}; // This used your "conversion" constructor

Related

Dangers of an explicit conversion operator with a 2nd implicit one in the same class

I find myself in a situation where I'm tempted to put two conversion operators in a single class. Normally I would avoid this like the plague. But with C++ 11 and explicit conversion operators, it seems what I want to achieve is both reasonable and safe. However I need a sanity check.
Consider the following class ("Distance") meant to tie together a distance value with its unit of measurement.
enum class Unit { None = 0, Meter = 1, Foot = 2, }; // None means INVALID
class Distance
{
Unit m_unit;
double m_value;
public:
Distance() : m_unit(Unit::None), m_value(0.f) {} // construct invalid
Distance(Unit u, double, v) : m_unit(u), m_value(v) {}
Unit unit() const { return m_unit; }
// Two functions that I would like to make into cast operators:
double value() const { return m_value; }
bool valid() const { return Unit::None != m_unit; }
// Cast operators I would LIKE to add and use. Implicitly cast to
// double but in "if()" scenarios, cast to bool to check validity
operator double() const { return m_value; }
explicit operator bool() { return valid(); }
};
Since a Distance object is meant to be treated as if it were a double value (most of the time), I considered adding the implicit double cast (above). But in certain contexts, a Distance can be considered "invalid", represented by a unit value of Unit::None. In that case I really like the idea of adding the explicit boolean cast.
The end goal is to be able replace code that currently reads like this:
void doSomething(bool b) {}
void doSomething(double d) {}
void DumpDistance(const Distance& dist)
{
if (dist.valid())
std::cout << dist.value() << std::endl;
doSomething(dist.valid()); // properly calls bool version
doSomething(dist.value()); // properly called double version
}
into this:
void DumpDistance(const Distance& dist)
{
if (dist) // treated as bool (good)
std::cout << dist << std::endl; // treated as double (good)
doSomething(dist); // calls double overload (good)
}
In my testing, it seems the explicit bool operator does the trick. But I'm not sure. It looks like the desired overloads are being called. But I have a built-in aversion to casting operators burned into me in dark old days of the 1990s.
So my question:
Is this really is as safe as it seems? Is there some obvious case I'm missing in which the compiler would complain about an ambiguous conversion or even worse, silently calls one operator when I wanted another?
(To be clear: I'm not asking about the necessity of this nor about its readability. Only about the dangers of compile-time ambiguities or conversions I don't want to happen. I need to solidify the concept of explicit conversion operators in my head. )

Assignment operator=

Suppose I have a class called Complex with 2 parameters real and imag. I want to overload the =(assignment) operator so that I could copy the value from the real parameter and assign it to an int.
If my main would look something like;
Complex z(1, 2);
int a = z;
I want a to be equal to 1.
How can I implement this function/method?
Use cast operator:
//Declaraion
class Complex {
operator int();
}
//Definition
Complex::operator int() {
return real_number;
}
Cast operator can implicitly convert a class instance to a certain type that is defined. It is a handy tool, but sometimes can be dangerous and vulnerable, and hard to debug.
When you define the assignment operator you are instructing the compiler on what to do when a value of possibly a different type is assigned to and instance of your class.
In this case instead you want to define what to do when an instance of your class is assigned to a variable of a different non-class type and this is not possible however. In other words it's the receiving instance that defines what to do in case of an assignment and you can customize this only for class types.
Something quite similar is instead to define how an instance of your class should be convertible to another type, e.g. how to convert a complex to an integer, and this conversion will be used also in case of assignment:
struct complex {
double real, imag;
...
operator int () const { return int(real); }
};
It isn't ideal to have code that reads as an assignment of types from different equivalence classes. It is correct that one should use casting instead, but the casting must be made explicit in C++11:
struct Complex {
double r, i;
...
explicit operator int () const { return int(r); }
};
Complex c = { 1.1, 2.2 };
float a = c; // fails with explicit
float a = (float)c; // fails with explicit
int a = c; // fails with explicit
int a = (int)c; // compiles with explicit
Do you really need to define a class for complex? It's part of standard library
Even you can see <complex> (#include <complex>) to find the operators and definitions overloaded
See more here

Type conversions to custom class - C++

I have a class of complex numbers, loaded the +, -, *, /,=,!= operators both with complex and double types on both ways but when I write the code complex z = 1, the compilers gives me an error saying that there are no variable conversion from int to complex. Although, it accepts the code
complex z;
z = 1;
and everything works fine. How can I fix this error?
The line complex z = 1 does Copy Initialization. You'll need an appropriate constructor:
complex::complex(int i) // or double or whatever is convertible to int by
{ // implicit conversion
// your code
}
This is different than
complex z;
z = 1;
which is assignment (to a previously default constructed object) that requires an assignment operator.
You may want add a constructor which accepts a double:
class complex
{
public:
complex(double d) : _real(d), _imag(0) { }
...
};
Be careful, though: this will make it possibly to pass an int wherever a complex is expected, because your constructor will perform an implicit conversion.
You need to write an appropriate constructor.
class complex {
public:
complex(double x) {
// ...
}
// ...
};
You need a constructor that takes a double.
class complex
{
public:
complex( double d );
};

Overloading static_cast?

So, I had an exam the other day, and one of the questions was something very similar to this:
We have a class called Square which holds a variable int side. How can we make it possible that cout << static_cast<int>(aSquare) <<endl; would print out the area of aSquare?
Is that even possible?
It's possible to make that work, but not via overloading static_cast<>(). You do so by overloading the typecast operator:
class Square
{
public:
Square(int side) : side(side) {}
operator int() const { return side * side; } // overloaded typecast operator
private:
int side;
};
// ...
// Compiler calls Square::operator int() to convert aSquare into an int
cout << static_cast<int>(aSquare) <<endl;
Beware that overloaded typecast operators more often than not tend to do more harm than good. They make lots of nonsensical implicit cast operations possible. When you read this code snippet below, do you think "a is going to get the area of s"?
Square aSquare;
int a = aSquare; // What the heck does this do?
I certainly don't. This makes way more sense and is much more readable:
Square aSquare;
int a = aSquare.GetArea();
Not to mention that typically you want to be able to access other information about Square, like GetSide() or GetApothem() or GetPerimeter() or whatever. operator int() obviously can return only one int, and you can't have multiple operator int()s as members of a class.
Here's another situation where the operator int() makes code that compiles yet makes no sense whatsoever:
Square s;
if(s > 42) {} // Huh?!
What does it mean for a Square to be greater than 42? It's nonsense, but with the operator int() the code above will compile as Shape is now convertible to an int which can be compared to another int with a value 4.
So don't write typecast operators like that. In fact if you're overloading typecast operators you may want to think twice about what you're doing. There's actually only a few cases where overloading the typecast operator is useful in modern C++ (e.g. the safe bool idiom).
You can overload the cast operator:
struct square {
operator int() const {
return (side * side);
}
int side;
};
The only problem is that it will be used implicitly, and casting doesn't make much sense here. You also can't distinguish between the different types of casts (static_cast, c-style, etc)
This is the preferred way to do things:
struct square {
int get_area() const {
return (side * side);
}
int side;
}
If you must use a cast, use C++11 feature and mark it explicit. This prevents implicit casting mistakes.
You could provide a conversion operator for the Square class:
class Square
{
public:
operator int()
{
return side * side;
}
private:
int side;
};

Deriving from a class with operator overloading

I want to create a collection of classes that behave like math vectors, so that multiplying an object by a scalar multiplies each field by that ammount, etc. The thing is that I want the fields to have actual names, instead of being treated as an index.
My original idea to implement this was creating a base class Rn with the overloads and then create derived classes with the pretty names. Something like this:
#include <iostream>
#include <algorithm>
using namespace std;
template<int N, class X=double>
struct Base{
X xs[N];
Base(){};
Base(X *data){
copy(data, data+N, xs);
}
Base operator*= (double d){
for(int i=0; i<N; i++){
xs[i] *= d;
}
return *this;
}
Base operator* (double d){
Base answer = *this;
answer *= d;
return answer;
}
//also operators for +=, +, multiplication from left, maybe [] too
};
struct Derived : public Base<2>{
Derived(double a, double b){
foo() = a;
bar() = b;
}
double &foo(){ return xs[0]; }
double &bar(){ return xs[1]; }
};
int main()
{
//this is OK:
double data[2] = {0.0, 2.0};
Base<2> b(data);
b = b*17.0;
cout << b.xs[0] << endl;
//I can't do this:
Derived x(0.0, 2.0);
x = x*17.0;
cout << x.foo() << endl;
return 0;
}
I get a compiler error whenever I try to use of of the operators that requires copying.
gcc gave me the following compiler error:
teste.cpp: In function ‘int main()’:
teste.cpp:52: error: no match for ‘operator=’ in ‘x = x.Derived::<anonymous>.Base<N, X>::operator* [with int N = 2, X = double](1.7e+1)’
teste.cpp:31: note: candidates are: Derived& Derived::operator=(const Derived&)
I think the problem is that the overloading functions deal with Base objects that can't be converted to Derived ones, so I can't use them in the derived class. However, I can't come up with a solution. Is there a way around this or should I use a totally different approach?
Bonus question: is there some way that I can use std::valarray to keep from having to type lots and lots of operator overloads?
Your Base operators (* in this case) can accept Derived object, but they return a Base, which can't be used as a right-hand operand in Derived default assignment operator. Easiest way to fix this is just add an assignment operator to Derive that will take a Base:
Derived& operator= (const Base<2>& other)
You will have to add it to any derived class, but the implementation is rather straightforward (you can have a void CopyOtherBase function in Base that will do the copy, and have all operator= call it and return *this).
I'll only address the technical difficulty, not whether this is a good idea or not.
The problem is that the result of operator* of Derived is a Base, and operator= of Derived (which is a default operator=) doesn't know how to "eat" a Base.
A simple solution is to create a constructor of Derived that gets a Base, and does whatever is needed to initialize itself correctly. This would allow an on-the-fly conversion of a Base to a Derived - and would work for all other operators of Derived that expect a Base.
Something along the lines of -
Derived(const Base<2>& B) : Base<2>( B )
{
}
I think you're going to be much better off using an enum or static constants to name your fields
e.g., static const int FIELD_NAME = 0;
Static const int FIELD_NAME2 = 1;
than doing this as different types (templates). Then you can go for std::valarray or boost::ublas::vector/matrix types to leverage existing code & get quality performance vector operations to boot.
Template metaprogramming had an interesting idea on solving just this sort of issue with math vectors, but perhaps doesn't solve your issue of naming the parts.
David Abrahams, Aleksey Gurtovoy: C++ Template Metaprogramming: Concepts, Tools, and Techniques from Boost and Beyond, Addison-Wesley, ISBN 0-321-22725-5
According to MSDN,
All overloaded operators except
assignment (operator=) are inherited
by derived classes.
Could this be your problem?