newbie: array of different classes

A

Allan Rydberg

hi

i have a series of pointer to different classes, such
as in:

class_a *cla;
cla = new class_a;
class_b *clb;
clb = new class_b;
class_c *clc;
clc = new class_c;
class_d *cld;
cld = new class_d;

for different reasons, i'd like to build an array of
pointers from the adresses of the classes, so i can
later call them from the array, using it's index. so
try something like this:

??pointer?? myClaArr[MAXCLASSES];
myClaArr[0] = cla;
myClaArr[1] = clb;
myClaArr[2] = clc;
myClaArr[3] = cld;

as i said, i'd like to be able to not only use the
functions directly as in clb->update(); but also the
call through the adresses in the array:

int active = 1;
myClaArr[active]->update();

how is this written correctly? i'm somehow tangled up with
the array and the adresses.

thanks a lot...
 
V

Victor Bazarov

Allan said:
i have a series of pointer to different classes, such
as in:

class_a *cla;
cla = new class_a;
class_b *clb;
clb = new class_b;
class_c *clc;
clc = new class_c;
class_d *cld;
cld = new class_d;

for different reasons, i'd like to build an array of
pointers from the adresses of the classes, so i can
later call them from the array, using it's index.

There is only one possible reason to do that and it's if your
classes are all descendants from a single class *and* your
array is an array of pointers to that class *and* you intend
to use those object polymorphically. Unless *all* conditions
are met, you have no reason to stuff them into the same array.

You could, of course, declare an array of 'void*' and stuff
your pointers there, but then you will most likely lose all
type information (unless you know that [0] is of type 'class_a'
and [1] is of type 'class_b', and this is hard-coded in your
program), and extracting them and using them becomes a rather
tedious business.
so
try something like this:

??pointer?? myClaArr[MAXCLASSES];
myClaArr[0] = cla;
myClaArr[1] = clb;
myClaArr[2] = clc;
myClaArr[3] = cld;

as i said, i'd like to be able to not only use the
functions directly as in clb->update(); but also the
call through the adresses in the array:

int active = 1;
myClaArr[active]->update();

how is this written correctly? i'm somehow tangled up with
the array and the adresses.

If you need 'update' to be called directly, research 'virtual'
and 'polymorphism'.

V
 
N

Noah Roberts

Allan said:
hi

i have a series of pointer to different classes, ...
for different reasons, i'd like to build an array of
pointers from the adresses of the classes, so i can
later call them from the array, using it's index.
myClaArr[active]->update();

how is this written correctly? i'm somehow tangled up with
the array and the adresses.

The syntax won't be exacly the same (as you have to do a cast) but you
can use boost::any to do what you want.
 
A

Allan Rydberg

Victor said:
There is only one possible reason to do that and it's if your
classes are all descendants from a single class *and* your
array is an array of pointers to that class *and* you intend
to use those object polymorphically. Unless *all* conditions
are met, you have no reason to stuff them into the same array.
isn't that true only if i want to stuff the classes themselves
into an array? what i want to achieve is to create only an array
of references to the class instances.

You could, of course, declare an array of 'void*' and stuff
your pointers there, but then you will most likely lose all
type information (unless you know that [0] is of type 'class_a'
and [1] is of type 'class_b', and this is hard-coded in your
program), and extracting them and using them becomes a rather
tedious business.
i sort of don't care about the type-info. all i need to do from
there is to call that xxx->update() function that exists within
every class independantly... is that possible at all? the lines
below sort of show the only thing i want to achieve with the
construct.

so
try something like this:

??pointer?? myClaArr[MAXCLASSES];
myClaArr[0] = cla;
myClaArr[1] = clb;
myClaArr[2] = clc;
myClaArr[3] = cld;

as i said, i'd like to be able to not only use the
functions directly as in clb->update(); but also the
call through the adresses in the array:

int active = 1;
myClaArr[active]->update();

how is this written correctly? i'm somehow tangled up with
the array and the adresses.

If you need 'update' to be called directly, research 'virtual'
and 'polymorphism'.


thnks.
 
B

Bart van Ingen Schenau

Allan said:
isn't that true only if i want to stuff the classes themselves
into an array? what i want to achieve is to create only an array
of references to the class instances.

When you have unrelated classes, any pointers that you create to those
classes will also be unrelated.
And C++ simply does not allow you to create an array of objects with
unrelated (or even related but different) types.
You could, of course, declare an array of 'void*' and stuff
your pointers there, but then you will most likely lose all
type information (unless you know that [0] is of type 'class_a'
and [1] is of type 'class_b', and this is hard-coded in your
program), and extracting them and using them becomes a rather
tedious business.
i sort of don't care about the type-info. all i need to do from
there is to call that xxx->update() function that exists within
every class independantly... is that possible at all? the lines
below sort of show the only thing i want to achieve with the
construct.

You may not care about the type information, but the compiler does.
The compiler needs that type information to verify that there is an
update() member-function that can be called with the provided
arguments, and the compiler also needs the type information to make
sure that the correct update() member-function gets called.

The only way around this, is to have a common base-class for your types,
like this:

class updatable {
public:
virtual void update(void) = 0;
};

class class_a : public updatable {
void update();
};

class class_b : public updatable {
void update();
};

updatable* myClaArr[MAXCLASSES];
so
try something like this:

??pointer?? myClaArr[MAXCLASSES];
myClaArr[0] = cla;
myClaArr[1] = clb;
myClaArr[2] = clc;
myClaArr[3] = cld;

as i said, i'd like to be able to not only use the
functions directly as in clb->update(); but also the
call through the adresses in the array:

int active = 1;
myClaArr[active]->update();

how is this written correctly? i'm somehow tangled up with
the array and the adresses.

If you need 'update' to be called directly, research 'virtual'
and 'polymorphism'.


thnks.

Bart v Ingen Schenau
 
H

Howard

Allan Rydberg said:
isn't that true only if i want to stuff the classes themselves
into an array? what i want to achieve is to create only an array
of references to the class instances.

But how do you know what those refer to? Just because each class type
contains a function called "update", that doesn't make the objects
compatibile. Pointers to different types of objects are themselves
different types of objects. That is, MyClass* is not compatible with
MyOtherClass*, unless MyOtherClass is a class derived from MyClass, and
you're using pointers of type MyClass*.
You could, of course, declare an array of 'void*' and stuff
your pointers there, but then you will most likely lose all
type information (unless you know that [0] is of type 'class_a'
and [1] is of type 'class_b', and this is hard-coded in your
program), and extracting them and using them becomes a rather
tedious business.
i sort of don't care about the type-info. all i need to do from
there is to call that xxx->update() function that exists within
every class independantly... is that possible at all? the lines
below sort of show the only thing i want to achieve with the
construct.
myClaArr[active]->update();

You _have_ to care about the type, if you want to use void* pointers.
Storing void* allows you to store different pointers, but you can't access
members (variables or functions) of the objects pointed to unless you cast
the void* pointer to the appropriate class first. That's because void*
contains no information about the class type, so there's no way for the
compiler to call the update() function for the correct class. It has to
know which class to use, in order to find the function to call.


-Howard
 
N

Noah Roberts

Allan said:
Victor Bazarov wrote:
You could, of course, declare an array of 'void*' and stuff
your pointers there, but then you will most likely lose all
type information (unless you know that [0] is of type 'class_a'
and [1] is of type 'class_b', and this is hard-coded in your
program), and extracting them and using them becomes a rather
tedious business.
i sort of don't care about the type-info. all i need to do from
there is to call that xxx->update() function that exists within
every class independantly... is that possible at all? the lines
below sort of show the only thing i want to achieve with the
construct.

You do want inheritance rather than boost::any it looks like.
Something akin to the following:

struct updatable
{
virtual void update() = 0;
};

class X : public virtual updatable
{
void update() { do_x(); }
};

class Y : public virtual updatable
{
void update() { do_y(); }
};

I don't know if the keyword virtual is needed in the inheritance in
this case as the function is abstract in updatable. I put it there
assuming that there could be cases when you inherit from two different
classes that both inherit from updatable; it is necissary to do so when
such is possible but I just don't know if it is still important when
the inherited class is purely abstract.
 
P

Puppet_Sock

Allan Rydberg wrote:
[snip]
i sort of don't care about the type-info. all i need to do from
there is to call that xxx->update() function that exists within
every class independantly... is that possible at all? the lines
below sort of show the only thing i want to achieve with the
construct.

In case what other people have said isn't clear, here's another
explanation.

Imagine you had only two classes you wanted to shove into
your array. One of them has one set of members, both
data and function members. The other has a different set.

So, when you come along with a pointer to the start of memory
where an instance of *something* is located, you have a problem.
How far into this chunk of memory is the "update" function?
(Or, probably, depending on the implementation, the location of
the update function code.) The first class looks like so:

blah blah blah
update
blah blah blah

And the second class looks like so:

yada yada yada yada yada yada yada yada yada yada yada yada
update
yada

Note that I deliberately put more stuff in front of the update in the
second case. And you really can't depend on that not happening
for different classes. You might have it happen in special cases,
say where the two classes had *exactly* the same set of function
members, and *exactly* the same set of data members, and
they were declared in *exactly* the same order. But I sure would
not count on it happening, even in that case. And just suppose
that you later come along and add "just one more variable." Boom!
Or you get a new compiler and the order changes. Boom!

Now you have a pointer stored in an array. How does your
compiler know where to look in the block of memory pointed
at by that pointer, in order to find the update function? The
answer is type information, inheritance, and polymorphism.
Socks
 
T

Thomas J. Gritzan

Allan said:
i sort of don't care about the type-info. all i need to do from
there is to call that xxx->update() function that exists within
every class independantly... is that possible at all?

Same question as in de.comp.lang.iso-c++, huh? :)

As you can't call update() or any other function on a void pointer, you
need one of:
1) pointers to a base class
2) some way to cast the objects down to the real type (ugly!)
3) some other way.

For 3), you could use either boost::variant (which I found more usefull
than boost::any) or something like this:

#include <iostream>
#include <vector>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
using boost::shared_ptr;
using boost::function;
using boost::bind;

struct classA
{
void update()
{
std::cout << "update classA" << std::endl;
}
};

struct classB
{
void update()
{
std::cout << "update classB" << std::endl;
}
};

struct object
{
object( shared_ptr<void> data_, function<void()> update_)
: data(data_), update(update_) {}

shared_ptr<void> data;
function<void()> update;
};

std::vector<object> myArray;

void callUpdate()
{
typedef std::vector<object>::iterator objItor;
for (objItor it = myArray.begin(); it != myArray.end(); it++)
it->update();
}

int main()
{
classA* a = new classA;
myArray.push_back( object(shared_ptr<void>(a), bind(&classA::update, a)) );

classB* b = new classB;
myArray.push_back( object(shared_ptr<void>(b), bind(&classB::update, b)) );

callUpdate();
}
 
R

RKS

Allan said:
hi

i have a series of pointer to different classes, such
as in:

class_a *cla;
cla = new class_a;
class_b *clb;
clb = new class_b;
class_c *clc;
clc = new class_c;
class_d *cld;
cld = new class_d;

for different reasons, i'd like to build an array of
pointers from the adresses of the classes, so i can
later call them from the array, using it's index. so
try something like this:

??pointer?? myClaArr[MAXCLASSES];
myClaArr[0] = cla;
myClaArr[1] = clb;
myClaArr[2] = clc;
myClaArr[3] = cld;

as i said, i'd like to be able to not only use the
functions directly as in clb->update(); but also the
call through the adresses in the array:

int active = 1;
myClaArr[active]->update();

how is this written correctly? i'm somehow tangled up with
the array and the adresses.

thanks a lot...


I would consider doing something like this..

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

class base
{
public:
virtual void Update()=0;
};
class A:public base
{
void Update()
{
cout<<"This is Class A::Update function"<<endl;
}
};
class B:public base
{
void Update()
{
cout<<"This is Class B::Update function"<<endl;
}
};

int main( void )
{
vector<base*> list;

A* a1=new A();
B* b1=new B();
list.push_back(a1);
list.push_back(b1);

vector<base*>::iterator it;
for(it=list.begin();it!=list.end();++it)
(*it)->Update();
cin.get();
return 0;
}
But it does require you to derive from a common base class like
everyone has already suggested. Hope this helps.
 
A

Allan Rydberg

thanks all for all these propsals... i get the point.
i guess there's no way around restructuring those classes
or (in my case) just hardcode switch/case routines...

greets!
 

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
474,141
Messages
2,570,813
Members
47,357
Latest member
sitele8746

Latest Threads

Top