classes in a class

J

Joe C

I have a class that performs transformations on data streams. As written,
the class constructor takes several parameters and a data-source to produce
it's stream.

I have the need to combine the output of two instances of this class to
generate a third data stream. (think eg of applying a filters to audio)

When I do this, the parameters that I supply the second class are dependent
upon the state of the system after the first transform has occured.

I have been accomplishing this by using a function outside the class that
instantiates the two classes as the information needed to instantiate them
becomes available. Once both objects are built, their output is combined
and the function exits, the objects are destroyed, and the caller gets his
transformed data.

I don't like this solution because my objects cease to exist once I return
the data...but I want to keem them around for a while longer.

So...as a solution, I decided to create a new class that would hold the two
instances of my transforming class objects and return the combined data. My
problem is...how can I construct my two member-data objects when the
construction parameters of the second object depend upon having made some
calculations on the first, successfully constructed object?

I can't supply the constructor parameters for the second object in the
initialization list because those parameters require some processing *after*
the first object is constructed.

Thanks for your thoughts

Joe
 
V

Victor Bazarov

Joe said:
I have a class that performs transformations on data streams. As written,
the class constructor takes several parameters and a data-source to produce
it's stream.

I have the need to combine the output of two instances of this class to
generate a third data stream. (think eg of applying a filters to audio)

When I do this, the parameters that I supply the second class are dependent
upon the state of the system after the first transform has occured.

I have been accomplishing this by using a function outside the class that
instantiates the two classes as the information needed to instantiate them
becomes available. Once both objects are built, their output is combined
and the function exits, the objects are destroyed, and the caller gets his
transformed data.

I don't like this solution because my objects cease to exist once I return
the data...but I want to keem them around for a while longer.

So...as a solution, I decided to create a new class that would hold the two
instances of my transforming class objects and return the combined data. My
problem is...how can I construct my two member-data objects when the
construction parameters of the second object depend upon having made some
calculations on the first, successfully constructed object?

I can't supply the constructor parameters for the second object in the
initialization list because those parameters require some processing *after*
the first object is constructed.

Make the second subobject a dynamic one and construct it using 'new':

class myclass {
myfirstauxiliaryclass aux1;
mysecondauxiliaryclass *paux2;
public:
myclass() : aux1(parameters) {
somecalculations(aux1);
paux2 = new mysecondauxiliaryclass(otherparameters);
}
};

Victor
 
J

Joe C

Victor Bazarov said:
class myclass {
myfirstauxiliaryclass aux1;
mysecondauxiliaryclass *paux2;
public:
myclass() : aux1(parameters) {
somecalculations(aux1);
paux2 = new mysecondauxiliaryclass(otherparameters);
}
};

Victor

Thanks Victor. This is exactly what I need. I guess it should have been
obvious to me but...well...it wasn't 8-\ Thanks again for 'getting' my
question, and giving me a straight forward solution.
 
C

Cy Edmunds

Joe C said:
Thanks Victor. This is exactly what I need. I guess it should have been
obvious to me but...well...it wasn't 8-\ Thanks again for 'getting' my
question, and giving me a straight forward solution.

It isn't quite as straight forward as you might think. The code as written
has a memory leak -- operator delete is never called. Of course you can add
a destructor with a delete statement, but then you really should add a copy
constructor and an assignment operator, remembering of course to avoid the
x=x bug in an exception-safe matter. No big deal, but still...

You could use a smart pointer, but it can also be done without any pointers
at all:

class two_things
{
private:
thing a;
thing b;
public:
two_things(arg_type arg) : a(arg), b(a) {}
// other stuff
};

This may look dangerous, but the standard guarantees that member variables
are intialized in the order they are declared. Thus a is constructed before
b and is safe to use as an argument for b's constructor.
 
V

Victor Bazarov

Cy Edmunds said:
It isn't quite as straight forward as you might think. The code as written
has a memory leak -- operator delete is never called. Of course you can
add
a destructor with a delete statement, but then you really should add a
copy
constructor and an assignment operator, remembering of course to avoid the
x=x bug in an exception-safe matter. No big deal, but still...

You could use a smart pointer, but it can also be done without any
pointers
at all:

class two_things
{
private:
thing a;
thing b;
public:
two_things(arg_type arg) : a(arg), b(a) {}
// other stuff
};

This may look dangerous, but the standard guarantees that member variables
are intialized in the order they are declared. Thus a is constructed
before
b and is safe to use as an argument for b's constructor.

Yes, and to perform that extra calculation you could declare a dummy member
and initialise it with the value returned by that calculation function:

class two_things
{
thing_one a;
int dummy;
thing_two b;

int some_extra_calculations(thing_one&);

public:
two_things(some_arguments)
: a(whatever)
, dummy(some_extra_calculations(a)
, b(something_else)
{
}
};

Given certain assumptions, everything is possible.

V
 
J

Joe C

Cy Edmunds said:
It isn't quite as straight forward as you might think. The code as written
has a memory leak -- operator delete is never called. Of course you can
add
a destructor with a delete statement, but then you really should add a
copy
constructor and an assignment operator, remembering of course to avoid the
x=x bug in an exception-safe matter. No big deal, but still...

Thanks for the comments. I used Vics method, and...as I guess Victor
guessed, we were on the same page regarding cleaning up memory.
You could use a smart pointer, but it can also be done without any
pointers
at all:

class two_things
{
private:
thing a;
thing b;
public:
two_things(arg_type arg) : a(arg), b(a) {}
// other stuff
};

This may look dangerous, but the standard guarantees that member variables
are intialized in the order they are declared. Thus a is constructed
before
b and is safe to use as an argument for b's constructor.
I don't think this technique will work, unless I modify the 'thing' class to
do the calculations that b needed...which doesn't make logical sense for
this class. I can't use your method because the method of generating the
parameters needed to instantiate b from a requires about 10 lines of code.
Anyway, thanks for offering another approach.
 
J

Joe C

Victor Bazarov said:
Yes, and to perform that extra calculation you could declare a dummy
member
and initialise it with the value returned by that calculation function:

class two_things
{
thing_one a;
int dummy;
thing_two b;

int some_extra_calculations(thing_one&);

public:
two_things(some_arguments)
: a(whatever)
, dummy(some_extra_calculations(a)
, b(something_else)
{
}
};

Given certain assumptions, everything is possible.

V

The class actually instantiates with a struct and a container ...the dummy
method would have gotten a little ugly. For this particular problem, I
think the pointer method you first offered was the more natural approach
compared to forcing it to happen in the initialization list. The only
downside is that one "thing" gets.treatment() while the other "thing"
gets->treatment() which is slightly awkward to have two very similar things
requiring different syntax. However, as this is hidden in the two_things
class, it doesn't really matter much.

Thanks guys.
 

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,767
Messages
2,569,571
Members
45,045
Latest member
DRCM

Latest Threads

Top