By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,853 Members | 1,046 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,853 IT Pros & Developers. It's quick & easy.

Avoiding rtti

P: n/a
I'm interested in computational physics and have defined an abstract base
class to represent a simulation. Now I want to develop a GUI for setting
the member data of classes derived from my base class.

I've approached this problem by creating a class named Interface with an
overloaded member function named addParameter():

class Interface {
public:
void addParameter( int& param );
void addParameter( double& param );
// etc.
};

Simulations call addParameter() on their data and the GUI works by keeping
pointers to the data. These pointers (along with other data to be displayed
by the GUI such as the name of the parameter, etc.) are stored in a
template struct named Parameter derived from a base class called
ParameterBase:

class ParameterBase {
virtual ~ParameterBase() {};
};

template<typename T>
struct Parameter : public ParameterBase {
T* data;
};

The GUI keeps track of these Parameters by managing a vector of
ParameterBase pointers, but this requires rtti. Can anyone suggest an
approach that doesn't?

I've also tried writing the Interface this way

class Interface {
public:
template<typename T>
void addParameter( T& param );
private:
template<typename T>
vector<T*>& parameters();
};

template<typename T>
vector<T*>& Interface::parameters()
{
static vector<T*> vec;
return vec;
}

template<typename T>
void Interface::addParameter( T& x )
{
parameters<T>().push_back( &x );
}

This avoids the problems associated with storing base class pointers, but
requires a way to keep track of what types addParameter() has been called
on. Furthermore I would still have to write code like

for( all the elements of parameters<int>() )
do_something

for( all the elements of parameters<double>() )
do_something

All comments are welcome.

Daniel
Jul 22 '05 #1
Share this Question
Share on Google+
4 Replies


P: n/a
Daniel Mitchell <da*********@mail.utexas.edu> wrote in
news:cc**********@geraldo.cc.utexas.edu:
The GUI keeps track of these Parameters by managing a vector of
ParameterBase pointers, but this requires rtti. Can anyone suggest an
approach that doesn't?


The visitor pattern.

#include <iostream>
#include <vector>

// --- Visitor ABS.

template <typename T> class Parameter;

struct Visitor {
virtual ~Visitor() { }
virtual void visit(Parameter<float>&) = 0;
virtual void visit(Parameter<double>&) = 0;
// ...
};

// --- Parameter base

struct ParameterBase {
virtual ~ParameterBase() {};
virtual void applyVisitor(Visitor&) = 0;
};

// --- Parameter implementation

template<typename T>
class Parameter : public ParameterBase {
T data;
public:
Parameter(T const& value) : data(value) { }
virtual void applyVisitor(Visitor& v) { v.visit(*this); }
};

// --- Visitor implementation

template <typename OStream>
class Printer : public Visitor {
OStream& out;
public:
Printer(OStream& out) : out(out) { }
virtual void visit(Parameter<float>& p) {
out << 'f' << ':' << p.data;
}
virtual void visit(Parameter<double>& p) {
out << 'd' << ':' << p.data;
}
// ...
};

// ---

int main() {
using namespace std;

vector<ParameterBase*> v;
v.push_back(new Parameter<float>(1.2f));
v.push_back(new Parameter<double>(0.1));

Printer<std::ostream> p(std::cout);
std::vector<ParameterBase*>::iterator it = v.begin();
for (; it != v.end(); ++it) {
(*it)->applyVisitor(p);
std::cout << ' ';
}
std::cout << '\n';

return 0;
}

Jul 22 '05 #2

P: n/a
On Fri, 2 Jul 2004 11:03:06 +0000 (UTC), bartek
<sp******************@o2.pl> wrote:

This won't compile:
#include <iostream>
#include <vector>

// --- Visitor ABS.

template <typename T> class Parameter;

struct Visitor {
virtual ~Visitor() { }
virtual void visit(Parameter<float>&) = 0;
virtual void visit(Parameter<double>&) = 0;
// ...
};

// --- Parameter base

struct ParameterBase {
virtual ~ParameterBase() {};
virtual void applyVisitor(Visitor&) = 0;
};

// --- Parameter implementation

template<typename T>
class Parameter : public ParameterBase {
T data;
public:
Parameter(T const& value) : data(value) { }
virtual void applyVisitor(Visitor& v) { v.visit(*this); }
};

// --- Visitor implementation

template <typename OStream>
class Printer : public Visitor {
OStream& out;
public:
Printer(OStream& out) : out(out) { }
virtual void visit(Parameter<float>& p) {
out << 'f' << ':' << p.data; ^^^^^^
p.data is not accessible to Visitor here because it is a private
member of Parameter.

Either make "data" public, or use a getter function, or make Visitor a
friend of Parameter, and it should compile.
}
virtual void visit(Parameter<double>& p) {
out << 'd' << ':' << p.data;
}
// ...
};

// ---

int main() {
using namespace std;

vector<ParameterBase*> v;
v.push_back(new Parameter<float>(1.2f));
v.push_back(new Parameter<double>(0.1));

Printer<std::ostream> p(std::cout);
std::vector<ParameterBase*>::iterator it = v.begin();
for (; it != v.end(); ++it) {
(*it)->applyVisitor(p);
std::cout << ' ';
}
std::cout << '\n';

return 0;
}

Who gets to delete the Parameter* that were created with "new"?

--
Bob Hairgrove
No**********@Home.com
Jul 22 '05 #3

P: n/a
Bob Hairgrove <wo**************@to.know> wrote in
news:hg********************************@4ax.com:
On Fri, 2 Jul 2004 11:03:06 +0000 (UTC), bartek
<sp******************@o2.pl> wrote:

This won't compile:
#include <iostream>
#include <vector>

// --- Visitor ABS.

template <typename T> class Parameter;

struct Visitor {
virtual ~Visitor() { }
virtual void visit(Parameter<float>&) = 0;
virtual void visit(Parameter<double>&) = 0;
// ...
};

// --- Parameter base

struct ParameterBase {
virtual ~ParameterBase() {};
virtual void applyVisitor(Visitor&) = 0;
};

// --- Parameter implementation

template<typename T>
class Parameter : public ParameterBase {
T data;
public:
Parameter(T const& value) : data(value) { }
virtual void applyVisitor(Visitor& v) { v.visit(*this); }
};

// --- Visitor implementation

template <typename OStream>
class Printer : public Visitor {
OStream& out;
public:
Printer(OStream& out) : out(out) { }
virtual void visit(Parameter<float>& p) {
out << 'f' << ':' << p.data; ^^^^^^
p.data is not accessible to Visitor here because it is a private
member of Parameter.

Either make "data" public, or use a getter function, or make Visitor a
friend of Parameter, and it should compile.


You're absolutely right. Thanks for pointing it out.
}
virtual void visit(Parameter<double>& p) {
out << 'd' << ':' << p.data;
}
// ...
};

// ---

int main() {
using namespace std;

vector<ParameterBase*> v;
v.push_back(new Parameter<float>(1.2f));
v.push_back(new Parameter<double>(0.1));

Printer<std::ostream> p(std::cout);
std::vector<ParameterBase*>::iterator it = v.begin();
for (; it != v.end(); ++it) {
(*it)->applyVisitor(p);
std::cout << ' ';
}
std::cout << '\n';

return 0;
}

Who gets to delete the Parameter* that were created with "new"?


Whoever writes real code will know what to do, I guess.

Perhaps I should have noted, that this code is just an approximate sample
of how a basic visitor is usually implemented. Not how to write proper
C++ code. I just hope that it wouldn't be really difficult for a person
who knows C++ to find it out.

Cheers.
Jul 22 '05 #4

P: n/a
> This avoids the problems associated with storing base class pointers, but
requires a way to keep track of what types addParameter() has been called
on. Furthermore I would still have to write code like

for( all the elements of parameters<int>() )
do_something

for( all the elements of parameters<double>() )
do_something

All comments are welcome.

Daniel

Why you didn't overload the member "do_something"? In this case you
would have:

for (forall elm in container)
{
elm.do_something (...);
}

Jul 22 '05 #5

This discussion thread is closed

Replies have been disabled for this discussion.