473,406 Members | 2,894 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,406 software developers and data experts.

how to make a simple class that is either an int or a float

Ben
Hi all,

I'm not yet good at thinking the right way in c++ so although I could
solve this problem, I'm not sure if they way I'm thinking of is the best
way to do it. I need a data type or class or something that can hold
either an int, or a float, knows which one it is holding, and will allow
me to do comparisons with instances of it without the code which asks
for the comparison having to know which one it is. So maybe I could do
it something like this (haven't compiled it so there are probably little
errors but hopefully you get the gist):

class Int_or_float {
int i;
float f;
bool is_int;
public:
bool Int_or_float::operator==( Int_or_float &a ) {
if( this->is_int ) return this->i == a.i;
else return this->f == a.f;
}
}

I could do it more simply perhaps like this:

class Int_or_float {
public:
int i;
float f;
bool is_int;
}

bool equal( Int_or_float x, y ) {
if( x.is_int ) return x.i == y.i;
else return x.f == y.f;
}

I realise neither of these will behave well if you compare one storing
an int with one storing a float.

So what are the pros and cons of each method? Is there an even simpler
method? I hoped I might be able to use a union but I can't think how. I
suppose if I want to use the STL I have no choice but to use the first
way?

Thanks in advance,

Ben

Jul 22 '05 #1
7 1835
"Ben" <be**************@zoology.ox.ac.uk> wrote in message
I'm not yet good at thinking the right way in c++ so although I could
solve this problem, I'm not sure if they way I'm thinking of is the best
way to do it. I need a data type or class or something that can hold
either an int, or a float, knows which one it is holding, and will allow
me to do comparisons with instances of it without the code which asks
for the comparison having to know which one it is. So maybe I could do
it something like this (haven't compiled it so there are probably little
errors but hopefully you get the gist):

class Int_or_float {
int i;
float f;
bool is_int;
public:
bool Int_or_float::operator==( Int_or_float &a ) {
if( this->is_int ) return this->i == a.i;
else return this->f == a.f;
}
}

I could do it more simply perhaps like this:

class Int_or_float {
public:
int i;
float f;
bool is_int;
}

bool equal( Int_or_float x, y ) {
if( x.is_int ) return x.i == y.i;
else return x.f == y.f;
}

I realise neither of these will behave well if you compare one storing
an int with one storing a float.

So what are the pros and cons of each method? Is there an even simpler
method? I hoped I might be able to use a union but I can't think how. I
suppose if I want to use the STL I have no choice but to use the first
way?

Thanks in advance,


This is actually a complicated problem. The first way is preferred as it
using private variables and encapsulation. But instead of a flag indicating
the type of an object, one should prefer to use virtual functions. The
standard solution is something like:

class Variable {
public:
virtual ~Variable() = 0;
virtual std::auto_ptr<Variable> clone() const = 0;
};

class Int : public Variable {
public:
Int(int data);
std::auto_ptr<Variable> clone() const;
private:
int d_data;
};

To handle comparing arbitrary types, one can use double dispatch. This is
when a (non-member usually) function is virtual in both its arguments. C++
does not provide native support for this, but you can build it yourself.
Look it up in the books or the internet. Here are the basics:

First, provide 4 operator== functinos, to compare Int to Int, Int to Double,
etc.

Basically you create a 2 by 2 matrix, or map, or whatever.

m["Int"]["Int"] maps to the function compare an Int to Int.
m["Int"]["Double"] maps to the function compare an Int to Double.

When the user calls operator==(variable1, variable2), look up the
appropriate function to call in the matrix map, then call it. If no
function found you throw an exception, or choose your favorite error
handling routine.

The advantage of this approach is that you can add new types, and all you
need is to derive a new class and provide the new equal functions, and store
these in the matrix.

But in your case you might not need double dispatch. Instead you could
provide a function asFloat() in the base variable class.

class Variable {
public:
virtual ~Variable() = 0;
virtual std::auto_ptr<Variable> clone() const = 0;
virtual double asDouble() const = 0;
};

inline
bool operator==(const Variable& lhs, const Variable&) {
return lhs.asDouble() == rhs.asDouble();
}
Jul 22 '05 #2
In article <1b******************@bgtnsc04-news.ops.worldnet.att.net>,
Siemel Naran <Si*********@REMOVE.att.net> wrote:
To handle comparing arbitrary types, one can use double dispatch. This is
when a (non-member usually) function is virtual in both its arguments. C++
does not provide native support for this, but you can build it yourself.
Look it up in the books or the internet. Here are the basics:

First, provide 4 operator== functinos, to compare Int to Int, Int to Double,
etc.

Basically you create a 2 by 2 matrix, or map, or whatever.

m["Int"]["Int"] maps to the function compare an Int to Int.
m["Int"]["Double"] maps to the function compare an Int to Double.

When the user calls operator==(variable1, variable2), look up the
appropriate function to call in the matrix map, then call it. If no
function found you throw an exception, or choose your favorite error
handling routine.

The advantage of this approach is that you can add new types, and all you
need is to derive a new class and provide the new equal functions, and store
these in the matrix.


There's an easier way to do double dispatch (especially for small sets
of possible types) that avoids having to explicitly determine the type
of objects by having a general method invoked on one class invoke a more
specific method in the other:

--------
class Value
{
public:
/*Return greater than, less than, or equal to 0 depending on whether
other's value is greater than, less than, or equal to ours
*/
virtual int compare(const Value& other) const =0;
protected:
virtual int compareWithInt(int other) const =0;
virtual int compareWithDouble(double other) const =0;
};

class IntValue
{
private:
int myInt;
public:
IntValue(int i):myInt(i) {}
virtual int compare(const Value& other) const
{return -other.compareWithInt(myInt);}
protected:
virtual int compareWithInt(int other) const
{return other<myInt?-1:(myInt==other?0:1);}
virtual int compareWithDouble(double other) const
{return other<myInt?-1:(myInt==other?0:1);}
};

class DoubleValue
{
private:
double myDouble;
public:
DoubleValue(int i):myDouble(i) {}
virtual int compare(const Value& other) const
{return -other.compareWithDouble(myDouble);}
protected:
virtual int compareWithInt(int other) const
{return other<myDouble?-1:(myDouble==other?0:1);}
virtual int compareWithDouble(double other) const
{return other<myDouble?-1:(myDouble==other?0:1);}
};

--------

(But for your specific problem, the idea upthread of just implementing
asDouble and calling that in the comparison is probably better than
using double dispatch.)
dave

--
Dave Vandervies dj******@csclub.uwaterloo.ca
Disagreeable intelligent folk make my day.
Of course, I'm biased.
--Brenda
Jul 22 '05 #3
Ben wrote:

Hi all,

I'm not yet good at thinking the right way in c++ so although I could
solve this problem, I'm not sure if they way I'm thinking of is the best
way to do it. I need a data type or class or something that can hold
either an int, or a float, knows which one it is holding, and will allow
me to do comparisons with instances of it without the code which asks
for the comparison having to know which one it is. So maybe I could do
it something like this (haven't compiled it so there are probably little
errors but hopefully you get the gist):

class Int_or_float {
int i;
float f;
bool is_int;
public:
bool Int_or_float::operator==( Int_or_float &a ) {
if( this->is_int ) return this->i == a.i;
else return this->f == a.f;
}
}

I could do it more simply perhaps like this:

class Int_or_float {
public:
int i;
float f;
bool is_int;
}

bool equal( Int_or_float x, y ) {
if( x.is_int ) return x.i == y.i;
else return x.f == y.f;
}

I realise neither of these will behave well if you compare one storing
an int with one storing a float.

So what are the pros and cons of each method? Is there an even simpler
method? I hoped I might be able to use a union but I can't think how. I
suppose if I want to use the STL I have no choice but to use the first
way?


If you want a minimalistic class and lightweight objects,
here is one sketch:

class Value {
enum Type {
type_int,
type_flt
};

union {
int v_int_;
float v_flt_;
};
int type_;

bool cmp_equal_type(Value const& rhs) const {
bool ret;
switch(type_) {
case type_int:
ret = v_int_ == rhs.v_int_;
break;
case type_flt:
ret = v_flt_ == rhs.v_flt_;
break;
default:
ret = false;//assert() or remove the option
}
return ret;
}

typedef double promote_t; //system-dependent

promote_t get_promoted() const {
promote_t ret;
switch(type_) {
case type_int:
ret = v_int_;
break;
case type_flt:
ret = v_flt_;
break;
default:
ret = 0;//assert() or remove the option
}
return ret;
}

public:
Value(int v) : v_int_(v), type_(type_int) {}
Value(float v) : v_flt_(v), type_(type_flt) {}

bool operator ==(Value const& rhs) const {
return rhs.type_ == type_? cmp_equal_type(rhs) :
(get_promoted() == rhs.get_promoted());
}

//...
};
Denis
Jul 22 '05 #4
Denis Remezov posted:
class Value {
enum Type {
type_int,
type_flt
};

union {
int v_int_;
float v_flt_;
};

What's the story with that? You haven't declared any variables/objects.

-JKop
Jul 22 '05 #5
Ben
Thanks very much for your suggestions folks...

I can just about get my head round the second suggestion. The first
suggestions is making me realise I have plenty more to learn - so I'll try!

Cheers,

Ben
Jul 22 '05 #6

"JKop" <NU**@NULL.NULL> wrote in message
news:q7*****************@news.indigo.ie...
Denis Remezov posted:
class Value {
enum Type {
type_int,
type_flt
};

union {
int v_int_;
float v_flt_;
};

What's the story with that? You haven't declared any variables/objects.

-JKop


It's called an anonymous union, v_int_ and v_flt_ are member variables of
class Value.

john
Jul 22 '05 #7
"Dave Vandervies" <dj******@csclub.uwaterloo.ca> wrote in message
news:cafu2h$nr6
Siemel Naran <Si*********@REMOVE.att.net> wrote:
To handle comparing arbitrary types, one can use double dispatch. This iswhen a (non-member usually) function is virtual in both its arguments. C++does not provide native support for this, but you can build it yourself.
Look it up in the books or the internet. Here are the basics:

First, provide 4 operator== functinos, to compare Int to Int, Int to Double,etc.

Basically you create a 2 by 2 matrix, or map, or whatever.

m["Int"]["Int"] maps to the function compare an Int to Int.
m["Int"]["Double"] maps to the function compare an Int to Double.

When the user calls operator==(variable1, variable2), look up the
appropriate function to call in the matrix map, then call it. If no
function found you throw an exception, or choose your favorite error
handling routine.

The advantage of this approach is that you can add new types, and all you
need is to derive a new class and provide the new equal functions, and storethese in the matrix.


There's an easier way to do double dispatch (especially for small sets
of possible types) that avoids having to explicitly determine the type
of objects by having a general method invoked on one class invoke a more
specific method in the other:

--------
class Value
{
public:
/*Return greater than, less than, or equal to 0 depending on whether
other's value is greater than, less than, or equal to ours
*/
virtual int compare(const Value& other) const =0;
protected:
virtual int compareWithInt(int other) const =0;
virtual int compareWithDouble(double other) const =0;
};


But this approach still suffers the disadvantage of not being as extensible.
Suppose you want to add a new type like Complex or String. With my proposed
code you just add your classes, new comparison functions, register these in
the double dispatch registry. With your approach we have to change the base
class to add new functions compareWithComplex and compareWithString.
(But for your specific problem, the idea upthread of just implementing
asDouble and calling that in the comparison is probably better than
using double dispatch.)


Right, in certain special cases we don't need the full blown double
dispatch.

Though who knows. There's a case for a special function here. Maybe to
compare two doubles we want to compare for approximatley equal, because two
doubles calculated through different formula may be slightly different
thanks to imperfect floating point math, example (1.0) and (1.0/3)*3.0 are
really both 1 but may be 1.0 and 0.9999* because of floating point math.
Jul 22 '05 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: Randi | last post by:
Hi, Looking for some help with this payrool project I have for class. This is what the instructor asks for so far. I have it working without errors but am getting some funky numbers. I am not...
12
by: Steven T. Hatton | last post by:
This is something I've been looking at because it is central to a currently broken part of the KDevelop new application wizard. I'm not complaining about it being broken, It's a CVS images. ...
8
by: Lou Pecora | last post by:
Problem: If I inherit an object B from A and use references in B to data in A, arrays of B objects which are pointed to by an A pointer causes "EXC_BAD_ACCESS" errors at the point shown in the...
4
by: hufel | last post by:
Hi, I'm doing my first big project in C# and I'm stuck with a problem that I believe has a simple and efficient solution for it (I just haven't bumped into it yet...). The concept is the...
24
by: firstcustomer | last post by:
Hi, Firstly, I know NOTHING about Javascript I'm afraid, so I'm hoping that someone will be able to point me to a ready-made solution to my problem! A friend of mine (honest!) is wanting to...
7
by: mathieu | last post by:
Hello, I did read the FAQ on template(*), since I could not find an answer to my current issue I am posting here. I have tried to summarize my issue in the following code (**). Basically I am...
5
by: frankb.mail | last post by:
Ok i'm new to C++ and am teaching myself i've hit a small block that I can't seem to get around I am trying to convert an array like std::string load; into a float array. The code looks...
1
by: Bl00dFox | last post by:
Hi I am making a simple program to calculate interest. At the beginning when the user has to pick 1 or 2 (to select simple or compound interest respectively), if the user enters a letter (eg, a)...
0
by: Andreas Schmitt | last post by:
I wrote a small timer class for use in a graphics engine I am working on for teaching myself. The small time based animations I tried with it seem to work fine but displaying the frame rate I...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.