Avoiding rtti

  • Thread starter Daniel Mitchell
  • Start date
D

Daniel Mitchell

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
 
B

bartek

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::eek:stream> 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;
}
 
B

Bob Hairgrove

#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::eek:stream> 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"?
 
B

bartek

^^^^^^
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.
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.
 
I

Idriz Smaili

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 (...);
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,197
Latest member
ScottChare

Latest Threads

Top