473,410 Members | 1,889 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,410 software developers and data experts.

Heterogeneous Container: avoid ifs and casts?

I defined a base class in order to put heterogeneous values into a
standard container: All values that I store in the container are
derived from my base class.

Now when I iterate over the elements of the container and want my
original values back - can I avoid excessive casting and if
statements? (see my sample code below.) Can I make it more elegant?

#include <iostream>
#include <vector>
using namespace std;

class Value{
public:
virtual ~Value(){}
};

template< typename T >
class SpecVal: public Value{
private:
T m_t;
public:
SpecVal (T const& t = T()): m_t(t) {}
T &getValue() {return m_t;}
};

void processString(const string &s){
cout << "String: " << s << endl;
}

void processFloat(const float &f){
cout << "Float: " << f << endl;
}

int main(){
vector<Value *> v;
v.push_back(new SpecVal<float>(3.5));
v.push_back(new SpecVal<string>("test"));
for(vector<Value *>::iterator i = v.begin(); i != v.end(); ++i){
if(SpecVal<float>* f = dynamic_cast<SpecVal<float>*>(*i)){
processFloat(f->getValue());
}else if(SpecVal<string>* s = dynamic_cast<SpecVal<string>*>(*i)){
processString(s->getValue());
}
delete *i;
}
}
Jul 22 '05 #1
8 2400
Markus Dehmann wrote:
I defined a base class in order to put heterogeneous values into a
standard container: All values that I store in the container are
derived from my base class. Now when I iterate over the elements of the container and want my
original values back - can I avoid excessive casting and if
statements? (see my sample code below.) Can I make it more elegant?
Generally, you need to read news:comp.object 's endless threads about
downcasting.

Specifically...
class Value{
public:
virtual ~Value(){}
virtual void stream(ostream & o) const = 0;
};


ostream & operator<<(ostream &o, Value const & val)
{
val.stream(o);
return o;
}

Now provide a custom implementation of stream() for each derived type.

The point of OO programming in general is to push interfaces up into
abstract class, and implementations down into concrete classes (and out into
delegates). So anything you plan to do generically to all Values deserves a
virtual method in the base class.

--
Phlip
http://industrialxp.org/community/bi...UserInterfaces
Jul 22 '05 #2
Markus Dehmann wrote:
I defined a base class in order to put heterogeneous values into a
standard container: All values that I store in the container are
derived from my base class.

Now when I iterate over the elements of the container and want my
original values back - can I avoid excessive casting and if
statements? (see my sample code below.) Can I make it more elegant?
The only way to make it more elegant is to define polymorphically
accessible interface and use it. I realise that it's not always
possible with straight types like 'int' and 'string', but do you
really expect so different types like your 'SpecVal<>', to somehow
usefully co-exist in the same container?

Depending on the purpose of this exercise, you might consider these
couple of opportunities. First solution, store the "type information"
in the class itself, so that you don't use the 'dynamic_cast<
SpecVal<string>* >()' ugliness, but instead use, say,

switch (i->getType()) {
case TYPE_STRING:
...
case TYPE_INT:

and so on. Of course, you will limit yourself to the number of
pre-defined type values and will have to let the base class know
what the derived classes are up to, which is against some principles
of OOD. Second, you could define 'toString' member in the 'Value'
class and always make your derived classes convert their stored
values to a string. That way you keep the straight interface, but
you incur the penalty of converting the values back and forth.

In any case, without knowing what precisely you're going to do with
the stored values, it's rather impossible to give perfect advice,
only guesses.

#include <iostream>
#include <vector>
using namespace std;

class Value{
public:
virtual ~Value(){}
};

template< typename T >
class SpecVal: public Value{
private:
T m_t;
public:
SpecVal (T const& t = T()): m_t(t) {}
T &getValue() {return m_t;}
};

void processString(const string &s){
cout << "String: " << s << endl;
}

void processFloat(const float &f){
cout << "Float: " << f << endl;
}

int main(){
vector<Value *> v;
v.push_back(new SpecVal<float>(3.5));
v.push_back(new SpecVal<string>("test"));
for(vector<Value *>::iterator i = v.begin(); i != v.end(); ++i){
if(SpecVal<float>* f = dynamic_cast<SpecVal<float>*>(*i)){
processFloat(f->getValue());
}else if(SpecVal<string>* s = dynamic_cast<SpecVal<string>*>(*i)){
processString(s->getValue());
}
delete *i;
}
}

Victor
Jul 22 '05 #3
On Tue, 01 Jun 2004 19:19:50 GMT, Phlip <ph*******@yahoo.com> wrote:
Markus Dehmann wrote:
I defined a base class in order to put heterogeneous values into a
standard container: All values that I store in the container are
derived from my base class.

Now when I iterate over the elements of the container and want my
original values back - can I avoid excessive casting and if
statements? (see my sample code below.) Can I make it more elegant?


Generally, you need to read news:comp.object 's endless threads about
downcasting.

Specifically...
class Value{
public:
virtual ~Value(){}


virtual void stream(ostream & o) const = 0;
};


ostream & operator<<(ostream &o, Value const & val)
{
val.stream(o);
return o;
}

Now provide a custom implementation of stream() for each derived type.


Thanks. Actually, I don't want to do anything with streams. I really want
the original float or string etc value back. Insofar, my code example was
misleading:

void processFloat(const float &f){
cout << "Float: " << f << endl;
}

It should be sth like:
float processFloat(const float &f){
return f * 10.0; // do sth with float
}
Jul 22 '05 #4
"Markus Dehmann" <ma*******@gmx.de> wrote in
news:op**************@news.cis.dfn.de:
On Tue, 01 Jun 2004 19:19:50 GMT, Phlip <ph*******@yahoo.com> wrote:
Markus Dehmann wrote:
I defined a base class in order to put heterogeneous values into a
standard container: All values that I store in the container are
derived from my base class.

Now when I iterate over the elements of the container and want my
original values back - can I avoid excessive casting and if
statements? (see my sample code below.) Can I make it more elegant?


Generally, you need to read news:comp.object 's endless threads about
downcasting.

Specifically...
class Value{
public:
virtual ~Value(){}


virtual void stream(ostream & o) const = 0;
};


ostream & operator<<(ostream &o, Value const & val)
{
val.stream(o);
return o;
}

Now provide a custom implementation of stream() for each derived
type.


Thanks. Actually, I don't want to do anything with streams. I really
want the original float or string etc value back. Insofar, my code
example was misleading:

void processFloat(const float &f){
cout << "Float: " << f << endl;
}

It should be sth like:
float processFloat(const float &f){
return f * 10.0; // do sth with float
}


Did you consider using the visitor pattern?

E.g. (derived from original example)

#include <vector>
#include <string>
#include <iostream>
#include <algorithm>

using std::vector;
using std::string;
using std::ostream;
using std::cout;
using std::for_each;

// need a forward decl.
template <class T> class SpecVal;

// visitor ABC
class Visitor {
public:
virtual ~Visitor() { }
virtual void operator()(SpecVal<float>&) const = 0;
virtual void operator()(SpecVal<string>&) const = 0;
};

// value ABC
class Value {
public:
virtual ~Value() { }
virtual void apply(Visitor const&) = 0;
};

// concrete value
template <class T>
class SpecVal : public Value {
T m_t;
public:
SpecVal(T const& t = T()) : m_t(t) { }
T& get() { return m_t; }
virtual void apply(Visitor const& v) { v(*this); }
};

// visitor implementation
class PrintVisitor : public Visitor {
ostream& out;
public:
PrintVisitor(ostream& out) : out(out) { }
virtual void operator()(SpecVal<float>& val) const
{ cout << "float:" << val.get() << '\n'; }
virtual void operator()(SpecVal<string>& val) const
{ cout << "string:" << val.get() << '\n'; }
};
int main() {
vector<Value*> v;

v.push_back(new SpecVal<float>(3.5f));
v.push_back(new SpecVal<string>("test"));

PrintVisitor visitor(cout);

vector<Value*>::iterator it(v.begin());
for (; it != v.end(); ++it)
(*it)->apply(visitor);

return 0;
}

--
:: bartekd [at] o2 [dot] pl

Jul 22 '05 #5
In article <qF*****************@newssvr32.news.prodigy.com> ,
"Phlip" <ph*******@yahoo.com> wrote:
Markus Dehmann wrote:
I defined a base class in order to put heterogeneous values into a
standard container: All values that I store in the container are
derived from my base class.

Now when I iterate over the elements of the container and want my
original values back - can I avoid excessive casting and if
statements? (see my sample code below.) Can I make it more elegant?


Generally, you need to read news:comp.object 's endless threads about
downcasting.

Specifically...
class Value{
public:
virtual ~Value(){}


virtual void stream(ostream & o) const = 0;
};


ostream & operator<<(ostream &o, Value const & val)
{
val.stream(o);
return o;
}

Now provide a custom implementation of stream() for each derived type.

The point of OO programming in general is to push interfaces up into
abstract class, and implementations down into concrete classes (and out into
delegates). So anything you plan to do generically to all Values deserves a
virtual method in the base class.


I agree with Philip, however there is another alternitive in this
case... 'boost::any' <www.boost.org> is probably worth looking into.
Jul 22 '05 #6
On Tue, 01 Jun 2004 19:03:32 -0400, "Markus Dehmann"
<ma*******@gmx.de> wrote:
Thanks. Actually, I don't want to do anything with streams. I really want
the original float or string etc value back.


But you want the value back in order to do something with it. Ideally,
put the operations in the base class interface. You can also use the
likes of the visitor pattern if the set of operations you want to
perform on Value types is unknown, but the set of Value subclasses is
known an finite.

If you're putting these values in a container together, there must be
something that you want to do to all of them. Value as written has no
behaviour - it is little better than using void* really. Give it the
behaviour you need from Values. What operations will you perform on
them?

Tom
--
C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Jul 22 '05 #7
On Tue, 01 Jun 2004 12:04:54 -0700, Markus Dehmann wrote:
I defined a base class in order to put heterogeneous values into a
standard container: All values that I store in the container are
derived from my base class.

Now when I iterate over the elements of the container and want my
original values back - can I avoid excessive casting and if
statements? (see my sample code below.) Can I make it more elegant?

#include <iostream>
#include <vector>
using namespace std;

class Value{
public:
virtual ~Value(){}
[quoted text muted]


template< typename T >
class SpecVal: public Value{
private:
T m_t;
public:
SpecVal (T const& t = T()): m_t(t) {}
T &getValue() {return m_t;}
[quoted text muted]


void processString(const string &s){
cout << "String: " << s << endl;
[quoted text muted]


void processFloat(const float &f){
cout << "Float: " << f << endl;
[quoted text muted]


int main(){
vector<Value *> v;
v.push_back(new SpecVal<float>(3.5));
v.push_back(new SpecVal<string>("test"));
for(vector<Value *>::iterator i = v.begin(); i != v.end(); ++i){
if(SpecVal<float>* f = dynamic_cast<SpecVal<float>*>(*i)){
processFloat(f->getValue());
}else if(SpecVal<string>* s = dynamic_cast<SpecVal<string>*>(*i)){
processString(s->getValue());
}
delete *i;
}
[quoted text muted]

How about this: implement an abstract class Value, with a
virtual void process() function. Then derive any type you need
from Value, and override the process() function. In more detail:

class Value
{
// private/protected members
public:
virtual void process() = 0;
// more public members.
};

class StringValue : public Value
{

public:
void process() { // Your processString() function here. };
};

class FloatValue : public Value
{

public:
void process() { // Your processFloat() function here. };
};

Then, in main()

vector<Value*> v;

// push back some Value* in v as needed;
// Initialize each one to the desired type:

v[0]=new StringValue("test");
v[1]=new FloatValue(3.5);

Then

v[0]->process(); // process string
v[1]->process(); // process float

That's the way I'd do it.

Jul 22 '05 #8
Typos, etc. corrected below.

bartek <sp******************@o2.pl> wrote in
news:Xn**********************************@153.19.2 51.200:
Did you consider using the visitor pattern?

E.g. (derived from original example)

#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
<algorithm> is not actually used...

using std::vector;
using std::string;
using std::ostream;
using std::cout;
using std::for_each;
std::for_each as well...
// need a forward decl.
template <class T> class SpecVal;

// visitor ABC
class Visitor {
public:
virtual ~Visitor() { }
virtual void operator()(SpecVal<float>&) const = 0;
virtual void operator()(SpecVal<string>&) const = 0;
};

// value ABC
class Value {
public:
virtual ~Value() { }
virtual void apply(Visitor const&) = 0;
};

// concrete value
template <class T>
class SpecVal : public Value {
T m_t;
public:
SpecVal(T const& t = T()) : m_t(t) { }
T& get() { return m_t; }
virtual void apply(Visitor const& v) { v(*this); }
};

// visitor implementation
class PrintVisitor : public Visitor {
ostream& out;
public:
PrintVisitor(ostream& out) : out(out) { }
virtual void operator()(SpecVal<float>& val) const
{ cout << "float:" << val.get() << '\n'; }
Of course, I made a typo in the above line ... should be:

{ out << "float:" << val.get() << '\n'; }

virtual void operator()(SpecVal<string>& val) const
{ cout << "string:" << val.get() << '\n'; }
Ditto...
{ out << "string:" << val.get() << '\n'; }
};
int main() {
vector<Value*> v;

v.push_back(new SpecVal<float>(3.5f));
v.push_back(new SpecVal<string>("test"));

PrintVisitor visitor(cout);

vector<Value*>::iterator it(v.begin());
for (; it != v.end(); ++it)
(*it)->apply(visitor);

return 0;
}


--
:: bartekd [at] o2 [dot] pl

Jul 22 '05 #9

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

Similar topics

1
by: kj | last post by:
The main rationale I have seen for namespace support in XML is to enable the peaceful coexistence of XML fragments from various sources within the same ("heterogeneous") XML document without their...
5
by: bg | last post by:
Hi! How do I check if "date" exists before using that code? I've built a RSSreader and sometimes there's a date in it and sometimes not. How can I check if it exists to avoid crash...
32
by: KK | last post by:
Hello all, I have a unsigned char buffer 'buffer' and I need to convert the first 12 bytes of it into a string. Below is a code that should work, however, how can I avoid reinterpret_cast...
16
by: Sensei | last post by:
Hi! I'm looking for something similar to the map container, but with a slight modification, a unique key, with multiple assignments to each one. I think some container in the STL has it, but I...
14
by: PengYu.UT | last post by:
In the following program, I want an iterator contain pointer pointing to constant object not const pointer. If it is possible would you please let me know how to do it? #include...
21
by: aaragon | last post by:
Hello everyone, I would like to know if there is a way to use the std::map to store different types for one of its two types. That is, I'm trying to use it as: typedef...
2
by: Arash Partow | last post by:
Hi all, I've got a question related to emulating aspects of polymorphism with CRTP. Below is a typical polymorphic class hierarchy with a definition of a "somewhat" heterogeneous container of...
6
by: rn5a | last post by:
What's the difference between <%# DataBinder.Eval(Container.DataItem,"LastName") %> & <%# Container.DataItem("LastName") %> Thanks
7
by: ademirzanetti | last post by:
Hi there !!! I would like to listen your opinions about inherit from a STL class like list. For example, do you think it is a good approach if I inherit from list to create something like...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
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
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
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
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
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...

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.