472,330 Members | 1,281 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 472,330 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 2328
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...
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...
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,...
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....
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...
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...
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...
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...
0
by: tammygombez | last post by:
Hey fellow JavaFX developers, I'm currently working on a project that involves using a ComboBox in JavaFX, and I've run into a bit of an issue....
0
by: concettolabs | last post by:
In today's business world, businesses are increasingly turning to PowerApps to develop custom business applications. PowerApps is a powerful tool...
0
better678
by: better678 | last post by:
Question: Discuss your understanding of the Java platform. Is the statement "Java is interpreted" correct? Answer: Java is an object-oriented...
0
by: teenabhardwaj | last post by:
How would one discover a valid source for learning news, comfort, and help for engineering designs? Covering through piles of books takes a lot of...
0
by: Naresh1 | last post by:
What is WebLogic Admin Training? WebLogic Admin Training is a specialized program designed to equip individuals with the skills and knowledge...
0
jalbright99669
by: jalbright99669 | last post by:
Am having a bit of a time with URL Rewrite. I need to incorporate http to https redirect with a reverse proxy. I have the URL Rewrite rules made...
0
by: antdb | last post by:
Ⅰ. Advantage of AntDB: hyper-convergence + streaming processing engine In the overall architecture, a new "hyper-convergence" concept was...
0
by: Matthew3360 | last post by:
Hi there. I have been struggling to find out how to use a variable as my location in my header redirect function. Here is my code. ...
0
by: AndyPSV | last post by:
HOW CAN I CREATE AN AI with an .executable file that would suck all files in the folder and on my computerHOW CAN I CREATE AN AI with an .executable...

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.