inheritance headache....



 DEVELOP > c-Plus-Plus > inheritance headache....

LINK TO THIS PAGE  


rating :  0   |  0


  Page 1 of 1

1

 
Topic: DEVELOP > c-Plus-Plus
User: ""
Date: 31 Jan 2008 03:53:07 PM
Object: inheritance headache....
Hi experts,
I have a construction problem that I need to fix;
currrently the following hierarchy exists;
abstractTarget
/ \
/ \
conreteTarget1 concreteTarget2
abstractDescription (this class family can NOT be modified)
/ \
concreteDesc1 concDesc1
Now somewhere, actually EVERYWHERE in this legacy code I see
statements like this;
// semi pseudo with
abstractTarget* createTarget(abstractDescription* desc)
{
// shortcut pseudo code for dynamic cast< > ()
if ( desc is concreteDesc1)
{
return new concreteTarget1();
}
else if (desc is concreteDesc2)
{
return new concreteTarget2();
}
else
{
return 0;
}
}
Now I CANT add methods to abstractDescription, if I could I would have
a method;
class abstractDescription
{
AbstractTarget* create(AbstractDescription* desc)
{
desc->create();
}
}
and each ConcreteDescription subclass would override as needed the
create the right concreteTarget.
BUT I cant do that as the AbstractDesciption family of objects cannot
be modified in any way. Can anybody help me out?
Im trying to tease out a solution here but I always get stung with a
cast or such like. anybody out there have any ideas?
cheers
G
.

User: "Alf P. Steinbach"

Title: Re: inheritance headache.... 31 Jan 2008 04:12:57 PM
* bob@blah.com:


I have a construction problem that I need to fix;


currrently the following hierarchy exists;



abstractTarget
/ \
/ \
conreteTarget1 concreteTarget2



abstractDescription (this class family can NOT be modified)
/ \
concreteDesc1 concDesc1


Now somewhere, actually EVERYWHERE in this legacy code I see
statements like this;

// semi pseudo with
abstractTarget* createTarget(abstractDescription* desc)
{

// shortcut pseudo code for dynamic cast< > ()
if ( desc is concreteDesc1)
{
return new concreteTarget1();
}
else if (desc is concreteDesc2)
{
return new concreteTarget2();
}
else
{
return 0;

}

}

Now I CANT add methods to abstractDescription, if I could I would have
a method;

class abstractDescription
{
AbstractTarget* create(AbstractDescription* desc)
{
desc->create();
}

}

It's clear what you mean, something like
struct AbstractDescription
{
virtual std::auto_ptr<AbstractTarget> create() const = 0;
};

and each ConcreteDescription subclass would override as needed the
create the right concreteTarget.

BUT I cant do that as the AbstractDesciption family of objects cannot
be modified in any way. Can anybody help me out?


Im trying to tease out a solution here but I always get stung with a
cast or such like. anybody out there have any ideas?

E.g. install factory functions in a std::map using typeinfo (from typeid
operator) as key. Then given an AbstractDescription, apply typid, look
up pointer in map, call resulting factory function. Only tricky thing
is to get that map properly initialized.
Cheers, & hth.,
- Alf
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
.
User: "James Kanze"

Title: Re: inheritance headache.... 01 Feb 2008 06:36:02 AM
On Jan 31, 11:12 pm, "Alf P. Steinbach" <al...@start.no> wrote:

* b...@blah.com:

class abstractDescription
{
AbstractTarget* create(AbstractDescription* desc)
{
desc->create();
}
}

It's clear what you mean, something like
struct AbstractDescription
{
virtual std::auto_ptr<AbstractTarget> create() const =3D 0;
};

How is it so clear? Normally, auto_ptr suggests that the caller
will be responsible for deleting the object. And most of the
time I've seen such a pattern used, this simply isn't the
case---the object registers itself in its constructor for some
sort of external events, and deletes itself when the appropriate
event arises.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34
.
User: "Alf P. Steinbach"

Title: Re: inheritance headache.... 01 Feb 2008 07:12:09 AM
* James Kanze:

On Jan 31, 11:12 pm, "Alf P. Steinbach" <al...@start.no> wrote:

* b...@blah.com:

class abstractDescription
{
AbstractTarget* create(AbstractDescription* desc)
{
desc->create();
}
}


It's clear what you mean, something like


struct AbstractDescription
{
virtual std::auto_ptr<AbstractTarget> create() const = 0;
};


How is it so clear? Normally, auto_ptr suggests that the caller
will be responsible for deleting the object.

Yes, that was the case.

And most of the
time I've seen such a pattern used, this simply isn't the
case---the object registers itself in its constructor for some
sort of external events, and deletes itself when the appropriate
event arises.

And that wasn't the case.
Cheers, & hth.,
- Alf
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
.
User: "James Kanze"

Title: Re: inheritance headache.... 01 Feb 2008 04:42:50 PM
On Feb 1, 2:12 pm, "Alf P. Steinbach" <al...@start.no> wrote:

* James Kanze:

On Jan 31, 11:12 pm, "Alf P. Steinbach" <al...@start.no> wrote:

* b...@blah.com:

class abstractDescription
{
AbstractTarget* create(AbstractDescription* desc)
{
desc->create();
}
}

It's clear what you mean, something like
struct AbstractDescription
{
virtual std::auto_ptr<AbstractTarget> create() const =3D 0;
};

How is it so clear? Normally, auto_ptr suggests that the caller
will be responsible for deleting the object.

Yes, that was the case.

How do you know? There was nothing in the original posting to
suggest it, and it's rather the exception, and not the rule.

And most of the
time I've seen such a pattern used, this simply isn't the
case---the object registers itself in its constructor for some
sort of external events, and deletes itself when the appropriate
event arises.

And that wasn't the case.

Again, how do you know? It's the more frequent case in well
designed software.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34
.
User: "Alf P. Steinbach"

Title: Re: inheritance headache.... 01 Feb 2008 05:35:42 PM
* James Kanze:

On Feb 1, 2:12 pm, "Alf P. Steinbach" <al...@start.no> wrote:

* James Kanze:

On Jan 31, 11:12 pm, "Alf P. Steinbach" <al...@start.no> wrote:

* b...@blah.com:

class abstractDescription
{
AbstractTarget* create(AbstractDescription* desc)
{
desc->create();
}
}


It's clear what you mean, something like


struct AbstractDescription
{
virtual std::auto_ptr<AbstractTarget> create() const = 0;
};


How is it so clear? Normally, auto_ptr suggests that the caller
will be responsible for deleting the object.


Yes, that was the case.


How do you know? There was nothing in the original posting to
suggest it, and it's rather the exception, and not the rule.

On the contrary, from the original posting:
* bob@blah.com:

Now somewhere, actually EVERYWHERE in this legacy code I see
statements like this;

// semi pseudo with
abstractTarget* createTarget(abstractDescription* desc)
{

// shortcut pseudo code for dynamic cast< > ()
if ( desc is concreteDesc1)
{
return new concreteTarget1();
}
else if (desc is concreteDesc2)
{
return new concreteTarget2();
}
else
{
return 0;
}
}

Notice that no information about the created objects is retained.
Hence, as I figure it, the caller has the responsibility for destroying
them.
Cheers, & hth.,
- Alf
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
.
User: "James Kanze"

Title: Re: inheritance headache.... 02 Feb 2008 04:20:41 AM
On Feb 2, 12:35 am, "Alf P. Steinbach" <al...@start.no> wrote:

* James Kanze:

[...]

How do you know? There was nothing in the original posting to
suggest it, and it's rather the exception, and not the rule.

On the contrary, from the original posting:
* b...@blah.com:

Now somewhere, actually EVERYWHERE in this legacy code I see
statements like this;
// semi pseudo with
abstractTarget* createTarget(abstractDescription* desc)
{
// shortcut pseudo code for dynamic cast< > ()
if ( desc is concreteDesc1)
{
return new concreteTarget1();
}
else if (desc is concreteDesc2)
{
return new concreteTarget2();
}
else
{
return 0;
}
}

Notice that no information about the created objects is retained.
Hence, as I figure it, the caller has the responsibility for destroying
them.

In other words, since no information is given, you suppose the
exceptional case, rather than the usual.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34
.
User: "Alf P. Steinbach"

Title: Re: inheritance headache.... 02 Feb 2008 04:50:09 AM
* James Kanze:

On Feb 2, 12:35 am, "Alf P. Steinbach" <al...@start.no> wrote:

* James Kanze:


[...]

How do you know? There was nothing in the original posting to
suggest it, and it's rather the exception, and not the rule.


On the contrary, from the original posting:


* b...@blah.com:

Now somewhere, actually EVERYWHERE in this legacy code I see
statements like this;


// semi pseudo with
abstractTarget* createTarget(abstractDescription* desc)
{
// shortcut pseudo code for dynamic cast< > ()
if ( desc is concreteDesc1)
{
return new concreteTarget1();
}
else if (desc is concreteDesc2)
{
return new concreteTarget2();
}
else
{
return 0;
}
}


Notice that no information about the created objects is retained.


Hence, as I figure it, the caller has the responsibility for destroying
them.


In other words, since no information is given, you suppose the
exceptional case, rather than the usual.

No. First, there's lots of information in the example above. Second,
what's "usual" for you is, I suspect, rather different than the norm in
industry, especially for old legacy code; a better term might be
"ideal", that you're wondering why I'm assuming the code isn't ideal...
Can you really imagine the programmer who created the above, doing
registration for events in e.g. concreteTarget1's constructor?
I can't -- but then, if the OP states otherwise (which would be
inconsistent with comments else-thread), I'd have to revise my opinion.
Cheers, & hth.,
- Alf
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
.
User: "James Kanze"

Title: Re: inheritance headache.... 05 Feb 2008 04:19:59 AM
On Feb 2, 11:50 am, "Alf P. Steinbach" <al...@start.no> wrote:

* James Kanze:

On Feb 2, 12:35 am, "Alf P. Steinbach" <al...@start.no> wrote:

* James Kanze:


[...]

How do you know? There was nothing in the original posting to
suggest it, and it's rather the exception, and not the rule.

On the contrary, from the original posting:
* b...@blah.com:

Now somewhere, actually EVERYWHERE in this legacy code I see
statements like this;
// semi pseudo with
abstractTarget* createTarget(abstractDescription* desc)
{
// shortcut pseudo code for dynamic cast< > ()
if ( desc is concreteDesc1)
{
return new concreteTarget1();
}
else if (desc is concreteDesc2)
{
return new concreteTarget2();
}
else
{
return 0;
}
}

Notice that no information about the created objects is retained.
Hence, as I figure it, the caller has the responsibility
for destroying them.

In other words, since no information is given, you suppose
the exceptional case, rather than the usual.

No. First, there's lots of information in the example above.
Second, what's "usual" for you is, I suspect, rather different
than the norm in industry, especially for old legacy code; a
better term might be "ideal", that you're wondering why I'm
assuming the code isn't ideal...

Or maybe the reverse. It was the usual pattern, in industry, 15
years ago, but it's true that I've not seen it presented in many
recent C++ texts.

Can you really imagine the programmer who created the above,
doing registration for events in e.g. concreteTarget1's
constructor?

Well, you may have a point there:-). Using a map of factory
objects was also a usual pattern in industry 15 years ago---if
the OP is unfamiliar with it, then maybe he's unfamiliar with
the other patterns as well.
Anyway, I think we agree in principle: if the constructor
registers the object (where ever), then a raw pointer is in
order. If it doesn't, then using an auto_ptr to hold the object
until it is registered is the more or less standard convention.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34
.

User: ""

Title: Re: inheritance headache.... 04 Feb 2008 12:23:16 PM
On Feb 2, 11:50=A0am, "Alf P. Steinbach" <al...@start.no> wrote:

* James Kanze:





On Feb 2, 12:35 am, "Alf P. Steinbach" <al...@start.no> wrote:

* James Kanze:


=A0 =A0 [...]

How do you know? =A0There was nothing in the original posting to
suggest it, and it's rather the exception, and not the rule.


On the contrary, from the original posting:


* b...@blah.com:

Now somewhere, actually EVERYWHERE in this legacy =A0code I see
statements like this;


// semi pseudo with
abstractTarget* createTarget(abstractDescription* desc)
{
// shortcut pseudo code for dynamic cast< > ()
=A0 =A0if ( desc is concreteDesc1)
=A0 =A0{
=A0 =A0 =A0return new concreteTarget1();
=A0 =A0}
=A0 =A0else if (desc is concreteDesc2)
=A0 =A0{
=A0 =A0 =A0return new concreteTarget2();
=A0 =A0}
=A0 =A0else
=A0 =A0{
=A0 =A0 =A0return 0;
=A0 =A0}
}


Notice that no information about the created objects is retained.


Hence, as I figure it, the caller has the responsibility for destroying=
them.


In other words, since no information is given, you suppose the
exceptional case, rather than the usual.


No. =A0First, there's lots of information in the example above. =A0Second,=
what's "usual" for you is, I suspect, rather different than the norm in
industry, especially for old legacy code; a better term might be
"ideal", that you're wondering why I'm assuming the code isn't ideal...

Can you really imagine the programmer who created the above, doing
registration for events in e.g. concreteTarget1's constructor?

I can't =A0-- =A0but then, if the OP states otherwise (which would be
inconsistent with comments else-thread), I'd have to revise my opinion.

Cheers, & hth.,

- Alf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?- Hide quoted t=

ext -


- Show quoted text -

you're correct Alf.
.






User: ""

Title: Re: inheritance headache.... 01 Feb 2008 09:14:23 AM
On Feb 1, 1:36=A0pm, James Kanze <james.ka...@gmail.com> wrote:

On Jan 31, 11:12 pm, "Alf P. Steinbach" <al...@start.no> wrote:

* b...@blah.com:

class abstractDescription
{
=A0 AbstractTarget* create(AbstractDescription* desc)
=A0 {
=A0 =A0 =A0 desc->create();
=A0 }
}

It's clear what you mean, something like
=A0 =A0struct AbstractDescription
=A0 =A0{
=A0 =A0 =A0 =A0virtual std::auto_ptr<AbstractTarget> create() const =3D =

0;

=A0 =A0};


How is it so clear? =A0Normally, auto_ptr suggests that the caller
will be responsible for deleting the object. =A0And most of the
time I've seen such a pattern used, this simply isn't the
case---the object registers itself in its constructor for some
sort of external events, and deletes itself when the appropriate
event arises.

--
James Kanze (GABI Software) =A0 =A0 =A0 =A0 =A0 =A0 email:james.ka...@gmai=

l.com

Conseils en informatique orient=E9e objet/
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0Beratung in objektorientierter Date=

nverarbeitung

9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34

this definitely has grabbed my attention as a potentially more elegant
solution. Does anybody have any docs/examples of this in action... I
would be delighted to read more. I was already thinking about this in
parallel... though am missing the details. At this stage I am very
much interested in the most elegant solution....performance is not an
issue (if that can ever be said when writing "elegant" code).
BTW Nobody needs to worry about auto_ptrs or memory mgmt here, Thats
all covered, the sample code/scenario is generalised/simplified.
Thanks *very* much for the input, I find the discussion very
interesting and revealing.
G
.
User: "James Kanze"

Title: Re: inheritance headache.... 01 Feb 2008 04:52:53 PM
On Feb 1, 4:14 pm, "b...@blah.com" <GrahamJWa...@gmail.com> wrote:

On Feb 1, 1:36 pm, James Kanze <james.ka...@gmail.com> wrote:

On Jan 31, 11:12 pm, "Alf P. Steinbach" <al...@start.no> wrote:

* b...@blah.com:

class abstractDescription
{
AbstractTarget* create(AbstractDescription* desc)
{
desc->create();
}
}

It's clear what you mean, something like
struct AbstractDescription
{
virtual std::auto_ptr<AbstractTarget> create() const =3D 0;
};

How is it so clear? Normally, auto_ptr suggests that the
caller will be responsible for deleting the object. And
most of the time I've seen such a pattern used, this simply
isn't the case---the object registers itself in its
constructor for some sort of external events, and deletes
itself when the appropriate event arises.

this definitely has grabbed my attention as a potentially more elegant
solution. Does anybody have any docs/examples of this in action... I
would be delighted to read more. I was already thinking about this in
parallel... though am missing the details. At this stage I am very
much interested in the most elegant solution....performance is not an
issue (if that can ever be said when writing "elegant" code).

Which is the elegant solution, what Alf suggested, or what I
suggested? Or perhaps better stated, what is the role of the
class in the application: my solution is generally applicable to
entity classes, but I use Alf's (or something similar, with my
own reference counted pointers) when I'm dealing with agents in
legacy applications (where I can't use the Boehm collector).
Anyway, my solution very much depends on how you manage the
objects in general. One typical case (at least in the type of
servers I work on) is where the objects are addresses from the
outside via some external name (DN or other); the constructor
registers the object in a map (std::map< DN, AbstractTarget* >)
so that the request handler can find it. Delete requests (like
all other requests) are forwarded to the object, which does a
delete this. The destructor removes the object from from the
map.
In another frequent idiom, the object will first be passed to a
transaction manager, which is responsible for deleting it until
the commit phase of the transaction, at which time it is
enrolled in the final registry.
In other cases, the object will register itself with an event
hander for some sort of external events; certain events will
tell the object that it is no longer needed, in which case, it
will delete itself (also deenrolling in the destructor).
In my experience, such scenarios represent the majority of
polymorphic objects.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34
.




User: "Grizlyk"

Title: Re: inheritance headache.... 02 Feb 2008 04:34:20 AM
wrote:


Now somewhere, actually EVERYWHERE in this legacy =A0code I see
statements like this;

// semi pseudo with
abstractTarget* createTarget(abstractDescription* desc)
{

// shortcut pseudo code for dynamic cast< > ()
=A0 =A0if ( desc is concreteDesc1)
=A0 =A0{
=A0 =A0 =A0return new concreteTarget1();
=A0 =A0}
=A0 =A0else if (desc is concreteDesc2)

you not need "else" after "return"

=A0 =A0{
=A0 =A0 =A0return new concreteTarget2();
=A0 =A0}
=A0 =A0else
=A0 =A0{
=A0 =A0 =A0return 0;

=A0 =A0}
}

Not sure about "actually EVERYWHERE", but the job is well-known design
pattern called as Abstract Factory.
The Factory returns concrete set of objects and knowledge about
correct type of returned objects is responsibility of the Factory,
encapsulated by the Factory, why "actually EVERYWHERE"?
Abstract Factory often used as link-time compatible part of program,
so implementation of the Factory is often runtime template (looks like
trivial case of well-known design pattern called as Template Method) -
removing implementation of interface of abstract base class into
derived classes.
Abstract Factory declare interface of creators:
class Abstract_Factory
{
public:
virtual
abstractTarget*
Abstract_Factory::createTarget
(abstractDescription* desc)
=3D0;
};
Concrete Factory, derived from Abstract Factory, encapsulates concrete
set of returned objects:
namespace N1feb2008{
class Concrete_Factory: public Abstract_Factory
{
public:
abstractTarget*
concrete_Factory::createTarget
(abstractDescription* desc)
{
if ( desc is concreteDesc1)
return new concreteTarget1;
if (desc is concreteDesc2)
return new concreteTarget2;
return 0;
}
};}
namespace N2feb2008{
template
<
class Told_Factory=3DN1feb2008::Concrete_Factory


class Concrete_Factory: public Abstract_Factory
{
Told_Factory old;
public:
abstractTarget*
concrete_Factory::createTarget
(abstractDescription* desc)
{
if ( desc is concreteDesc3)
return new concreteTarget3;
return old.createTarget(desc);
}
};}

Now I CANT add methods to abstractDescription,
if I could I would have a method;

class abstractDescription
{
=A0 AbstractTarget* create(AbstractDescription* desc)
=A0 {
=A0 =A0 =A0 desc->create();
=A0 }
}

and each ConcreteDescription subclass would override
as needed the create the right concreteTarget.

BUT I cant do that as the AbstractDesciption family
of objects cannot be modified in any way.

Not sure what does it mean "cannot be modified in any way". There is
well-known design pattern Adapter, that can adapt in fact everything
to everywhere.
In the case, Adapter will add to abstractDescription new method for
new "create" message of new requested interface (class
Adapted_Description).
//compile time template
namespace Nctt
{
//types
//they encapsulate links
//between Target and Description
template<class Tadapted>
struct Tlink;
//
template<>struct
Tlink<concreteDescription1>
{ typedef concreteTarget1 Target; };
//
template<>struct
Tlink<concreteDescription2>
{ typedef concreteTarget2 Target; };
//
template<>struct
Tlink<concreteDescription3>
{ typedef concreteTarget3 Target; };
//end of types
//adapter
template<class Tadapted, class Towner=3DTadapted>
class Adapted_Description: public abstractDescription
{
public:
typedef
typename Tlink<Tadapted>::Target
Target;
protected:
Towner adapted;
//new interface
public:
Target* create()
{ return new Target; }
Adapted_Description();
Adapted_Description(const Towner& ad):
adapted(ad);
//old interface
public:
for each
abstractDescription::method
{ adapted.abstractDescription::method; }
};
//namespace Nctt
}
//run time template
namespace Nrtt
{
class Adapted_Description: public abstractDescription
{
//new interface
public:
virtual
AbstractTarget*
create()
=3D0;
};
template<class Tadapted, class Towner=3DTadapted>
class concrete_Description: public Adapted_Description
{
public:
typedef
typename Nctt::Adapted_Description
<Tadapted, Towner>
Nctt_Adapted_Description;
typedef
typename
Nctt_Adapted_Description::Target
Target;
protected:
Nctt_Adapted_Description
adapted;
//Ncct::Adapted_Description interface
for each
Nctt_Adapted_Description ctor
{ concrete_Description():adapted(); }
/*
concrete_Description()
adapted();
concrete_Description(const Towner& ad):
adapted(ad);
*/
/*
//new interface (part of Adapted_Description interface)
public:
Target*
create()
{ return adapted.create(); }
*/
//old interface
public:
for each
Adapted_Description::method
{ adapted.Ncct_Adapted_Description::method; }
};
//namespace Nrtt
}
This can be compiled
void foo()
{
Nctt::Adapted_Description
<concreteDescription1>
tmp;
Nrtt::concrete_Description
<concreteDescription1>
tmp2;
tmp.create();
tmp2.create();
}
declare and define all
class abstractDescription{};
class AbstractTarget{};
class concreteDescription1:
public abstractDescription {};
class concreteDescription2:
public abstractDescription {};
class concreteDescription3:
public abstractDescription {};
class concreteTarget1:
public AbstractTarget {};
class concreteTarget2:
public AbstractTarget {};
class concreteTarget3:
public AbstractTarget {};
and comment "for each" sections and not-defined ctors
Maksim A. Polyanin
http://grizlyk1.narod.ru/cpp_new
.
User: "Grizlyk"

Title: Re: inheritance headache.... 02 Feb 2008 05:02:44 AM
Grizlyk wrote:


//adapter
template<class Tadapted, class Towner=Tadapted>
class Adapted_Description: public abstractDescription

Well, i forget to say, that often CTT will be not derived from
abstractDescription.
In fact, only follwing code was not-virtual


//new interface
public:
Target* create()
{ return new Target; }

So, there is example of total not-virtual class-adapter
//adapter
template<class Tadapted, class Towner=Tadapted>
class Adapted_Description
{
...
//old interface
public:
for each
adapted::method
//not-virtual call
{ adapted.adapted::method; }
};
Maksim A. Polyanin
http://grizlyk1.narod.ru/cpp_new
--
Message posted using http://www.talkaboutprogramming.com/group/comp.lang.c++/
More information at http://www.talkaboutprogramming.com/faq.html
.
User: "Grizlyk"

Title: Re: inheritance headache.... 02 Feb 2008 05:21:16 AM

for each
adapted::method
//not-virtual call
{ adapted.adapted::method; }

No
{ adapted.Tadapted::method; }
--
Message posted using http://www.talkaboutprogramming.com/group/comp.lang.c++/
More information at http://www.talkaboutprogramming.com/faq.html
.



User: "tragomaskhalos"

Title: Re: inheritance headache.... 31 Jan 2008 04:17:43 PM
On 31 Jan, 21:53, "b...@blah.com" <GrahamJWa...@gmail.com> wrote:

Hi experts,

I have a construction problem that I need to fix;

Now somewhere, actually EVERYWHERE in this legacy =A0code I see
statements like this;

// semi pseudo with
abstractTarget* createTarget(abstractDescription* desc)
{
// shortcut pseudo code for dynamic cast< > ()
=A0 =A0if ( desc is concreteDesc1)
=A0 =A0{
=A0 =A0 =A0return new concreteTarget1();
=A0 =A0}
=A0 =A0else if (desc is concreteDesc2)
=A0 =A0{
=A0 =A0 =A0return new concreteTarget2();
=A0 =A0}
=A0 =A0else
=A0 =A0{
=A0 =A0 =A0return 0;
=A0 =A0}
}

Now I CANT add methods to abstractDescription, if I could I would have
a method;

It's not clear from your post if it's the *same* type-switching
code being used to create concrete objects, or different
flavours of type-switching code doing a variety of things.
If it's the former, the best you can do is refactor to a
single createTarget method - and, ugly as it is, I don't
see how to significantly improve what you have within the
constraints cited (assuming there are indeed only 2 subclasses
involved - if there are rather more, there are better ways
than a succession of if statements).
.

User: "Sean Hunt"

Title: Re: inheritance headache.... 31 Jan 2008 10:10:41 PM
On Jan 31, 2:53 pm, "b...@blah.com" <GrahamJWa...@gmail.com> wrote:

Hi experts,

I have a construction problem that I need to fix;

currrently the following hierarchy exists;

abstractTarget
/ \
/ \
conreteTarget1 concreteTarget2

abstractDescription (this class family can NOT be modified)
/ \
concreteDesc1 concDesc1

Now somewhere, actually EVERYWHERE in this legacy code I see
statements like this;

// semi pseudo with
abstractTarget* createTarget(abstractDescription* desc)
{

// shortcut pseudo code for dynamic cast< > ()

You can compare type_id

if ( desc is concreteDesc1)
{
return new concreteTarget1();
}
else if (desc is concreteDesc2)
{
return new concreteTarget2();
}
else
{
return 0;

}

}

Now I CANT add methods to abstractDescription, if I could I would have
a method;

class abstractDescription
{
AbstractTarget* create(AbstractDescription* desc)
{
desc->create();
}

}

and each ConcreteDescription subclass would override as needed the
create the right concreteTarget.

BUT I cant do that as the AbstractDesciption family of objects cannot
be modified in any way. Can anybody help me out?

Use a map of typeid:
// You will need every target to have a static create() method.
#include <typeinfo>
// Comparison operator
bool compare (const std::type_info & lhs, const std::type_info & rhs)
{
return lhs.before(rhs);
}
//Map
std::map <const std::type_info &, abstractTarget (*) ()> type_map;
void initialize_type_map()
{
type_map[typeid(concreteDesc1)] = &concreteTarget1::create;
type_map[typeid(concreteDesc2)] = &concreteTarget2::create;
}
Then you can just write:
absractTarget* target = mymap[typeid(desc)]();
You could also have a wrapper class to hide all of this stuff.

Im trying to tease out a solution here but I always get stung with a
cast or such like. anybody out there have any ideas?

cheers

G

NOTE: The previous post was made incomplete. Sorry about that.
.
User: "Triple-DES"

Title: Re: inheritance headache.... 01 Feb 2008 01:34:13 AM
On 1 Feb, 05:10, Sean Hunt <ride...@gmail.com> wrote:

//Map
std::map <const std::type_info &, abstractTarget (*) ()> type_map;

void initialize_type_map()
{
=A0 type_map[typeid(concreteDesc1)] =3D &concreteTarget1::create;
=A0 type_map[typeid(concreteDesc2)] =3D &concreteTarget2::create;

}

Remember that you can't have containers of references. To make the
type_map work here you need it to operate on std::type_info pointers
(with a predicate that compares the pointers in terms of the "before"
member function), or write a small wrapper class for std::type_info.
.

User: ""

Title: Re: inheritance headache.... 01 Feb 2008 01:25:18 AM
Thanks for the replies. To answer some questions/remarks;
1) There are a good few concreteTarget and concreteDescription
subclasses and there will be lots more added in the months to come.
This means the
if ( desc is concreteDesc1)
{
return new concreteTarget1();
}
else if (desc is concreteDesc2)
{
return new concreteTarget2();
}
else
{
return 0;
}
control statements will get out of control.
"It's not clear from your post if it's the *same* type-switching
code being used to create concrete objects, or different
flavours of type-switching code doing a variety of things."
Its actually both. Throughout the code, ConcreteTarget objects are
created using the logic above and also to perform various method
invocations. For the moment, I'm just concerned about the creation of
the obejcts. I think the smartest solution so far is perhaps that
provide by Sean Hunt (thanks Sean). I could wrap the code and put it
into a factory object.
If anybody has anything to add, I'm all ears. I'm thinking there HAS
to be a smarter way. I really want to avoid any sort of lookup or if/
else if logic as I've been reading up on my OO design books. Martin
Fowlers refactoring book doesn't cover it. Gamma et Al don't deal with
this scenario in Design Patterns and I didn't have time to look at my
copy of "Working with Legacy Code" last night as it was 11pm and I
wanted a beer! :) :)
Anyways, thanks for the inputs. If anybody has any more wicked ideas
on this conundrum, I'd be DELIGHTED to hear.
Thanks again,
G
On Feb 1, 5:10=A0am, Sean Hunt <ride...@gmail.com> wrote:

On Jan 31, 2:53 pm, "b...@blah.com" <GrahamJWa...@gmail.com> wrote:





Hi experts,


I have a construction problem that I need to fix;


currrently the following hierarchy exists;


=A0 =A0 =A0 =A0abstractTarget
=A0 =A0 =A0 =A0/ =A0 =A0 =A0 =A0 =A0 \
=A0 =A0 =A0 / =A0 =A0 =A0 =A0 =A0 =A0 \
=A0conreteTarget1 =A0concreteTarget2


=A0 =A0 =A0 =A0abstractDescription (this class family can NOT be modifie=

d)

=A0 =A0 =A0 =A0 =A0/ =A0 =A0 =A0 =A0 =A0\
=A0 =A0concreteDesc1 =A0concDesc1


Now somewhere, actually EVERYWHERE in this legacy =A0code I see
statements like this;


// semi pseudo with
abstractTarget* createTarget(abstractDescription* desc)
{


// shortcut pseudo code for dynamic cast< > ()


You can compare type_id





=A0 =A0if ( desc is concreteDesc1)
=A0 =A0{
=A0 =A0 =A0return new concreteTarget1();
=A0 =A0}
=A0 =A0else if (desc is concreteDesc2)
=A0 =A0{
=A0 =A0 =A0return new concreteTarget2();
=A0 =A0}
=A0 =A0else
=A0 =A0{
=A0 =A0 =A0return 0;


=A0 =A0}


}


Now I CANT add methods to abstractDescription, if I could I would have
a method;


class abstractDescription
{
=A0 AbstractTarget* create(AbstractDescription* desc)
=A0 {
=A0 =A0 =A0 desc->create();
=A0 }


}


and each ConcreteDescription subclass would override as needed the
create the right concreteTarget.


BUT I cant do that as the AbstractDesciption family of objects cannot
be modified in any way. Can anybody help me out?


Use a map of typeid:

// You will need every target to have a static create() method.

#include <typeinfo>

// Comparison operator
bool compare (const std::type_info & lhs, const std::type_info & rhs)
{
=A0 return lhs.before(rhs);

}

//Map
std::map <const std::type_info &, abstractTarget (*) ()> type_map;

void initialize_type_map()
{
=A0 type_map[typeid(concreteDesc1)] =3D &concreteTarget1::create;
=A0 type_map[typeid(concreteDesc2)] =3D &concreteTarget2::create;

}

Then you can just write:
absractTarget* target =3D mymap[typeid(desc)]();

You could also have a wrapper class to hide all of this stuff.

Im trying to tease out a solution here but I always get stung with a
cast or such like. anybody out there have any ideas?


cheers


G


NOTE: The previous post was made incomplete. Sorry about that.- Hide quote=

d text -


- Show quoted text -- Hide quoted text -

- Show quoted text -

.


User: "Sean Hunt"

Title: Re: inheritance headache.... 31 Jan 2008 10:03:36 PM
On Jan 31, 2:53 pm, "b...@blah.com" <GrahamJWa...@gmail.com> wrote:

Hi experts,

I have a construction problem that I need to fix;

currrently the following hierarchy exists;

abstractTarget
/ \
/ \
conreteTarget1 concreteTarget2

abstractDescription (this class family can NOT be modified)
/ \
concreteDesc1 concDesc1

Now somewhere, actually EVERYWHERE in this legacy code I see
statements like this;

// semi pseudo with
abstractTarget* createTarget(abstractDescription* desc)
{

// shortcut pseudo code for dynamic cast< > ()
if ( desc is concreteDesc1)

Don't use dynamic_cast to check whether a class is of a specific type.
Only use it if you need the actual dervied object - otherwise, use
typeid:
if (typeid(desc) == typeid(concreteDesc1))
typeid will return an std::type_info object corresponding to the most
derived type. Remember to include <typeinfo> before using typeid!

{
return new concreteTarget1();
}
else if (desc is concreteDesc2)
{
return new concreteTarget2();
}
else
{
return 0;

}

}

Now I CANT add methods to abstractDescription, if I could I would have
a method;

class abstractDescription
{
AbstractTarget* create(AbstractDescription* desc)
{
desc->create();
}

}

and each ConcreteDescription subclass would override as needed the
create the right concreteTarget.

BUT I cant do that as the AbstractDesciption family of objects cannot
be modified in any way. Can anybody help me out?

As far as I know, there's no way to properly reproduce the virtual
call mechanism. However, a map of typeids will work:
bool operator <

Im trying to tease out a solution here but I always get stung with a
cast or such like. anybody out there have any ideas?

cheers

G

.
User: "James Kanze"

Title: Re: inheritance headache.... 01 Feb 2008 06:57:58 AM
On Feb 1, 5:03 am, Sean Hunt <ride...@gmail.com> wrote:
[...]

// semi pseudo with
abstractTarget* createTarget(abstractDescription* desc)
{


// shortcut pseudo code for dynamic cast< > ()
if ( desc is concreteDesc1)

Don't use dynamic_cast to check whether a class is of a
specific type. Only use it if you need the actual dervied
object - otherwise, use typeid:
if (typeid(desc) =3D=3D typeid(concreteDesc1))
typeid will return an std::type_info object corresponding to
the most derived type. Remember to include <typeinfo> before
using typeid!

The semantics are different. Use typeid if you want to know the
exact most derived type, dynamic_cast if you only want to know
whether the object is a, or not. (In this case, I suspect that
the desired semantics are in fact those of typeid, and not
dynamic_cast.)
[...]

As far as I know, there's no way to properly reproduce the virtual
call mechanism. However, a map of typeids will work:
bool operator <

Two gotcha's for mapping type_info's to anything:
1. A type_info is not copiable, so you can't put them in a
container. You need to use type_info const*.
2. type_info, per se, doesn't support operator<. You need to
provide your own, based on type_info::before(). (Hopefully,
the next version of the standard will correct this, and also
provide functions for =3D=3D and getting a hash code of a
type_info.)
For these reasons, I tend to use a wrapper class, something
like:
class Type
{
public:
/* implicit */ Type( std::type_info const& type )
: myType( &type )
{
}
bool operator<( Type const& other ) const
{
return myType->before( *other.myType ) ;
}
private:
std::type_info const*myType ;
} ;
typedef std::map< Type, whatever >
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34
TypeMap ;
.
User: "Pete Becker"

Title: Re: inheritance headache.... 01 Feb 2008 08:09:28 AM
On 2008-02-01 07:57:58 -0500, James Kanze <james.kanze@gmail.com> said:

2. type_info, per se, doesn't support operator<. You need to
provide your own, based on type_info::before(). (Hopefully,
the next version of the standard will correct this, and also
provide functions for == and getting a hash code of a
type_info.)

It's not going to happen if nobody proposes it. (that's a hint...)
--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
Standard C++ Library Extensions: a Tutorial and Reference
(www.petebecker.com/tr1book)
.
User: "James Kanze"

Title: Re: inheritance headache.... 01 Feb 2008 04:54:35 PM
On Feb 1, 3:09 pm, Pete Becker <p...@versatilecoding.com> wrote:

On 2008-02-01 07:57:58 -0500, James Kanze <james.ka...@gmail.com> said:

2. type_info, per se, doesn't support operator<. You need to
provide your own, based on type_info::before(). (Hopefully,
the next version of the standard will correct this, and also
provide functions for =3D=3D and getting a hash code of a
type_info.)

It's not going to happen if nobody proposes it. (that's a hint...)

If it's not too late, I'll write one up this week-end. (I
really wanted to contribute a lot more, but I've had problems
finding the time. So when something small like this presents
itself... At least I can do something.)
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34
.
User: "Pete Becker"

Title: Re: inheritance headache.... 01 Feb 2008 05:35:19 PM
On 2008-02-01 17:54:35 -0500, James Kanze <james.kanze@gmail.com> said:

On Feb 1, 3:09 pm, Pete Becker <p...@versatilecoding.com> wrote:

On 2008-02-01 07:57:58 -0500, James Kanze <james.ka...@gmail.com> said:


2. type_info, per se, doesn't support operator<. You need to
provide your own, based on type_info::before(). (Hopefully,
the next version of the standard will correct this, and also
provide functions for == and getting a hash code of a
type_info.)


It's not going to happen if nobody proposes it. (that's a hint...)


If it's not too late, I'll write one up this week-end.

It never hurts to ask.

(I
really wanted to contribute a lot more, but I've had problems
finding the time. So when something small like this presents
itself... At least I can do something.)

<g>
--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
Standard C++ Library Extensions: a Tutorial and Reference
(www.petebecker.com/tr1book)
.





User: ""

Title: Re: inheritance headache.... 04 Feb 2008 03:11:30 PM
On Jan 31, 4:53=A0pm, "b...@blah.com" <GrahamJWa...@gmail.com> wrote:

Hi experts,

I have a construction problem that I need to fix;

currrently the following hierarchy exists;

=A0 =A0 =A0 =A0abstractTarget
=A0 =A0 =A0 =A0/ =A0 =A0 =A0 =A0 =A0 \
=A0 =A0 =A0 / =A0 =A0 =A0 =A0 =A0 =A0 \
=A0conreteTarget1 =A0concreteTarget2

=A0 =A0 =A0 =A0abstractDescription (this class family can NOT be modified)=
=A0 =A0 =A0 =A0 =A0/ =A0 =A0 =A0 =A0 =A0\
=A0 =A0concreteDesc1 =A0concDesc1

Now somewhere, actually EVERYWHERE in this legacy =A0code I see
statements like this;

// semi pseudo with
abstractTarget* createTarget(abstractDescription* desc)
{

// shortcut pseudo code for dynamic cast< > ()
=A0 =A0if ( desc is concreteDesc1)
=A0 =A0{
=A0 =A0 =A0return new concreteTarget1();
=A0 =A0}
=A0 =A0else if (desc is concreteDesc2)
=A0 =A0{
=A0 =A0 =A0return new concreteTarget2();
=A0 =A0}
=A0 =A0else
=A0 =A0{
=A0 =A0 =A0return 0;

=A0 =A0}

}

Now I CANT add methods to abstractDescription, if I could I would have
a method;

class abstractDescription
{
=A0 AbstractTarget* create(AbstractDescription* desc)
=A0 {
=A0 =A0 =A0 desc->create();
=A0 }

}

and each ConcreteDescription subclass would override as needed the
create the right concreteTarget.

BUT I cant do that as the AbstractDesciption family of objects cannot
be modified in any way. Can anybody help me out?

Im trying to tease out a solution here but I always get stung with a
cast or such like. anybody out there have any ideas?

cheers

G

As others have pointed out, you should use a factory.
First cut, put the if statement inside a factory and
keep that logic in exactly one place instead of all
over your code.
Second cut, you can have your concrete classes register
their creation methods with the factory so you can
eliminate the if statement. Modern C++ Design has a
good example of how to do this.
One of the problems in your above code is that you are
passing an already constructed desc class into the
contructor of the target class. But it looks like there
is a one-to-one correspondence between target classes and
desc class. That means you can have the target class
constructor just create it's appropriate desc class
If that's not possible, then I'd go with the typeid as
someone else has suggested.
.


  Page 1 of 1

1

 


Related Articles
 

NEWER

pg.1232     pg.940     pg.716     pg.544     pg.412     pg.311     pg.234     pg.175     pg.130     pg.96     pg.70     pg.50     pg.35     pg.24     pg.16     pg.10     pg.6     pg.3     pg.1

OLDER