|
|
|
|
||||||
![]() |
|
|
LinkBack | Outils de la discussion |
|
|
#1 |
|
Messages: n/a
Hébergeur: |
I've been facing this situation often:
class NewFeature { TheClass *theClass; NewFeature(TheClass *t) { theClass = t; } void act() { // call methods on theClass } } class TheClass { NewFeature *feature; // More commonly, a list of NewFeature objects AddFeature(NewFeature *f) { feature = f; // or append f to a list of NewFeature objects } } In the above case, TheClass class contains pointers to NewFeature objects, and each NewFeature object contains a pointer to the same TheClass instance. This does seem to work most of the time but I'm not comfortable with the idea of this circular reference. Is there a standard design pattern to overcome this? The closest I saw was visitor pattern. If I use that here, I'd do something like class NewFeature { TheClass *theClass; void accept(TheClass *t) { theClass = t; } void act() { // call methods on theClass } } class TheClass { AddFeature(NewFeature *f) { f->accept(this); f->act(); } } But in this case, I'm losing the ability to keep track of the NewFeature objects I have. Especially, if NewFeature.act() runs some thread that calls TheClass methods later, I want TheClass to be able to start / stop the thread when I want; so maintaining a list of those pointers will be useful. If I do, I end up having my earlier code. Please ! |
|
|
|
#2 |
|
Messages: n/a
Hébergeur: |
On Dec 6, 10:01 pm, Karthik V <karthikveeram...@gmail.com> wrote:
> I've been facing this situation often: > > class NewFeature > { > TheClass *theClass; > NewFeature(TheClass *t) { theClass = t; } > void act() { // call methods on theClass } > > } > > class TheClass > { > NewFeature *feature; // More commonly, a list of NewFeature objects > AddFeature(NewFeature *f) { feature = f; // or append f to a list of > NewFeature objects } > > } > > In the above case, TheClass class contains pointers to NewFeature > objects, and each NewFeature object contains a pointer to the same > TheClass instance. This does seem to work most of the time but I'm not > comfortable with the idea of this circular reference. > > Is there a standard design pattern to overcome this? The closest I saw > was visitor pattern. If I use that here, I'd do something like > > class NewFeature > { > TheClass *theClass; > void accept(TheClass *t) { theClass = t; } > void act() { // call methods on theClass } > > } > > class TheClass > { > AddFeature(NewFeature *f) { f->accept(this); f->act(); } > > } > > But in this case, I'm losing the ability to keep track of the > NewFeature objects I have. Especially, if NewFeature.act() runs some > thread that calls TheClass methods later, I want TheClass to be able > to start / stop the thread when I want; so maintaining a list of those > pointers will be useful. If I do, I end up having my earlier code. > > Please ! There is nothing wrong with using your method. You have just keeping a pointer to the object and not the actual object thus you have no circular reference. All the pointer is in the most general sense is an integer. Using the actual object would be bad though as this would be like having a nested class structure and lead to looping in compilation. |
|
|
|
#3 |
|
Messages: n/a
Hébergeur: |
adam.madram@gmail.com a écrit :
> On Dec 6, 10:01 pm, Karthik V <karthikveeram...@gmail.com> wrote: >> I've been facing this situation often: >> >> class NewFeature >> { >> TheClass *theClass; >> NewFeature(TheClass *t) { theClass = t; } >> void act() { // call methods on theClass } >> >> } >> >> class TheClass >> { >> NewFeature *feature; // More commonly, a list of NewFeature objects >> AddFeature(NewFeature *f) { feature = f; // or append f to a list of >> NewFeature objects } >> >> } >> >> In the above case, TheClass class contains pointers to NewFeature >> objects, and each NewFeature object contains a pointer to the same >> TheClass instance. This does seem to work most of the time but I'm not >> comfortable with the idea of this circular reference. From a pure design point of view, you are right that it smells. But sometimes, it is the more natural way of doing rather than go through complex construction. This often happen, as in your case a class owning a feature, when an object has to keep a pointer on the object that owns it. The only difficulty is lifetime issues: making the difference when a object is destroyed by the object that own its or by other mean; there are many strategy to adresse that. >> Is there a standard design pattern to overcome this? The closest I saw >> was visitor pattern. Visitor tends to increase coupling between classes. I am pretty sure it is not what you want. The right solution greatly depends on what you want to achieve and the environment you work in. A generic solution (not the best for you) is defining an interface class that is taken in parameter by a NewFeature. TheClass would inherit from this interface and pass itself in parameter to the NewFeature. >> If I use that here, I'd do something like >> >> class NewFeature >> { >> TheClass *theClass; >> void accept(TheClass *t) { theClass = t; } >> void act() { // call methods on theClass } >> >> } >> >> class TheClass >> { >> AddFeature(NewFeature *f) { f->accept(this); f->act(); } >> >> } >> >> But in this case, I'm losing the ability to keep track of the >> NewFeature objects I have. Especially, if NewFeature.act() runs some >> thread that calls TheClass methods later, I want TheClass to be able >> to start / stop the thread when I want; so maintaining a list of those >> pointers will be useful. If I do, I end up having my earlier code. You could also lookup "observer pattern" and signal/slot idiom. You could also split your classes; it seems to me that TheClass has a lot of responsibilities :start/stop thread, provides functions called into the thread. I can't you there, it is your design. >> > > There is nothing wrong with using your method. You have just keeping a > pointer to the object and not the actual object thus you have no > circular reference. All the pointer is in the most general sense is an > integer. Using the actual object would be bad though as this would be > like having a nested class structure and lead to looping in > compilation. The OP problem is not from a compilation point of view but rather a design issue. Michael |
|
|
|
#4 |
|
Messages: n/a
Hébergeur: |
On Dec 7, 12:08 am, Michael DOUBEZ <michael.dou...@free.fr> wrote:
> adam.mad...@gmail.com a écrit : > > > > > On Dec 6, 10:01 pm, Karthik V <karthikveeram...@gmail.com> wrote: > >> I've been facing this situation often: > > >> class NewFeature > >> { > >> TheClass *theClass; > >> NewFeature(TheClass *t) { theClass = t; } > >> void act() { // call methods on theClass } > > >> } > > >> class TheClass > >> { > >> NewFeature *feature; // More commonly, a list of NewFeature objects > >> AddFeature(NewFeature *f) { feature = f; // or append f to a list of > >> NewFeature objects } > > >> } > > >> In the above case, TheClass class contains pointers to NewFeature > >> objects, and each NewFeature object contains a pointer to the same > >> TheClass instance. This does seem to work most of the time but I'm not > >> comfortable with the idea of this circular reference. > > From a pure design point of view, you are right that it smells. But > sometimes, it is the more natural way of doing rather than go through > complex construction. > > This often happen, as in your case a class owning a feature, when an > object has to keep a pointer on the object that owns it. The only > difficulty is lifetime issues: making the difference when a object is > destroyed by the object that own its or by other mean; there are many > strategy to adresse that. > > >> Is there a standard design pattern to overcome this? The closest I saw > >> was visitor pattern. > > Visitor tends to increase coupling between classes. I am pretty sure it > is not what you want. > > The right solution greatly depends on what you want to achieve and the > environment you work in. > A generic solution (not the best for you) is defining an interface class > that is taken in parameter by a NewFeature. TheClass would inherit from > this interface and pass itself in parameter to the NewFeature. > > > > >> If I use that here, I'd do something like > > >> class NewFeature > >> { > >> TheClass *theClass; > >> void accept(TheClass *t) { theClass = t; } > >> void act() { // call methods on theClass } > > >> } > > >> class TheClass > >> { > >> AddFeature(NewFeature *f) { f->accept(this); f->act(); } > > >> } > > >> But in this case, I'm losing the ability to keep track of the > >> NewFeature objects I have. Especially, if NewFeature.act() runs some > >> thread that calls TheClass methods later, I want TheClass to be able > >> to start / stop the thread when I want; so maintaining a list of those > >> pointers will be useful. If I do, I end up having my earlier code. > > You could also lookup "observer pattern" and signal/slot idiom. You > could also split your classes; it seems to me that TheClass has a lot of > responsibilities :start/stop thread, provides functions called into the > thread. > I can't you there, it is your design. > > > > > There is nothing wrong with using your method. You have just keeping a > > pointer to the object and not the actual object thus you have no > > circular reference. All the pointer is in the most general sense is an > > integer. Using the actual object would be bad though as this would be > > like having a nested class structure and lead to looping in > > compilation. > > The OP problem is not from a compilation point of view but rather a > design issue. > > Michael Michael and Adam, Thanks a lot! As Michael said, the main concern was destroying the object. Since the NewFeature can be extended and implemented by anyone, there is a potential possibility of that code invoking a Destroy() on TheClass. I was wondering if there is a way to prevent that. Michael, the way I have it now, TheClass is just an interface, not the concrete implementation. So I guess I'm following that practice already. |
|
|
|
#5 |
|
Messages: n/a
Hébergeur: |
Karthik V a écrit :
> Michael and Adam, > > Thanks a lot! As Michael said, the main concern was destroying the > object. Since the NewFeature can be extended and implemented by > anyone, there is a potential possibility of that code invoking a > Destroy() on TheClass. I was wondering if there is a way to prevent > that. Declare the destructor of TheClass protected. > > Michael, the way I have it now, TheClass is just an interface, not the > concrete implementation. So I guess I'm following that practice > already. Michael |
|
|
|
#6 |
|
Messages: n/a
Hébergeur: |
On Dec 9, 12:47 am, Michael DOUBEZ <michael.dou...@free.fr> wrote:
> Karthik V a écrit : > > > Michael and Adam, > > > Thanks a lot! As Michael said, the main concern was destroying the > > object. Since the NewFeature can be extended and implemented by > > anyone, there is a potential possibility of that code invoking a > > Destroy() on TheClass. I was wondering if there is a way to prevent > > that. > > Declare the destructor of TheClass protected. > > > > > Michael, the way I have it now, TheClass is just an interface, not the > > concrete implementation. So I guess I'm following that practice > > already. > > Michael why not to refrence count 'TheClass'(e.g using boost::shared_ptr)? regards, FM. |
|
|
|
#7 |
|
Messages: n/a
Hébergeur: |
On Dec 7, 9:08 am, Michael DOUBEZ <michael.dou...@free.fr> wrote:
> adam.mad...@gmail.com a écrit : > > On Dec 6, 10:01 pm, Karthik V <karthikveeram...@gmail.com> wrote: > >> I've been facing this situation often: > >> class NewFeature > >> { > >> TheClass *theClass; > >> NewFeature(TheClass *t) { theClass = t; } > >> void act() { // call methods on theClass } > >> } > >> class TheClass > >> { > >> NewFeature *feature; // More commonly, a list of NewFeature objects > >> AddFeature(NewFeature *f) { feature = f; // or append f to a list of > >> NewFeature objects } > >> } > >> In the above case, TheClass class contains pointers to NewFeature > >> objects, and each NewFeature object contains a pointer to the same > >> TheClass instance. This does seem to work most of the time but I'm not > >> comfortable with the idea of this circular reference. > From a pure design point of view, you are right that it smells. But > sometimes, it is the more natural way of doing rather than go through > complex construction. Why? It looks like a more or less standard implementation of the strategy pattern. Most of the time, the strategy elements---the NewFeature here---don't need a reference to the parent, but I don't see any particular problem when they do. Most of the time, of course, NewFeature will be an abstract base class; in such cases, it's often simplest to make it a member class of TheClass. (Not that this changes much in overall view.) > This often happen, as in your case a class owning a feature, > when an object has to keep a pointer on the object that owns > it. The only difficulty is lifetime issues: making the > difference when a object is destroyed by the object that own > its or by other mean; there are many strategy to adresse that. The usual solution is to have the TheClass construct the NewFeature, via some special function, and then own it, deleting it in its destructor. > >> Is there a standard design pattern to overcome this? The > >> closest I saw was visitor pattern. > Visitor tends to increase coupling between classes. I am > pretty sure it is not what you want. I don't think it's what he's looking for either, but not because of coupling. In his case, the coupling is there (since NewFeature depends on TheClass). In the past, I've used a variant of this several times, in which NewFeature was an abstract base class, member and friend of TheClass, and it provided an extended interface to TheClass, so that user code could implement a wide variety of strategies. > >> If I use that here, I'd do something like > > >> class NewFeature > >> { > >> TheClass *theClass; > >> void accept(TheClass *t) { theClass = t; } > >> void act() { // call methods on theClass } > >> } > >> class TheClass > >> { > >> AddFeature(NewFeature *f) { f->accept(this); f->act(); } > >> } > >> But in this case, I'm losing the ability to keep track of > >> the NewFeature objects I have. If the NewFeature objects are polymorphic (and I don't see very well how they could not be), then in practice, they'll all be allocated on the stack. The usual solution in my code is just to let the garbage collector take care of them, but if for some reason you cannot use garbage collection, it's typically not too much of a constraint to require them to be unique to each instance, and have TheClass take over ownership, and delete them in the destructor. (I'd document this by having the function which registers them take an auto_ptr.) Some sort of reference counting could also be used, but typically, it's overkill. > >> Especially, if NewFeature.act() runs some thread that calls > >> TheClass methods later, I want TheClass to be able to start > >> / stop the thread when I want; so maintaining a list of > >> those pointers will be useful. If I do, I end up having my > >> earlier code. If the NewFeature uses worker threads, you have a whole lot of additional issues to address. Like what happens if the TheClass object is deleted before the worker thread has finished. One solution I've used at times is to make the destructor of TheClass private, and require calling a special member function to destroy the object. This function marks the object as "dead", and puts it on a queue for destruction; actual destruction only occurs when the last worker thread has finished. It's not a universal solution, however, and isn't always appropriate. (Trying to do multithreading without garbage collection is just plain stupid.) > You could also lookup "observer pattern" and signal/slot > idiom. You could also split your classes; it seems to me that > TheClass has a lot of responsibilities :start/stop thread, > provides functions called into the thread. I can't you > there, it is your design. Making the observer pattern work well between threads is far from trivial. -- James Kanze (GABI Software) email:james.kanze@gmail.com Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34 |
|
|
|
#8 |
|
Messages: n/a
Hébergeur: |
On Dec 9, 12:48 pm, terminator <farid.mehr...@gmail.com> wrote:
> On Dec 9, 12:47 am, Michael DOUBEZ <michael.dou...@free.fr> wrote: > > Karthik V a écrit : > > > Michael and Adam, > > > Thanks a lot! As Michael said, the main concern was destroying the > > > object. Since the NewFeature can be extended and implemented by > > > anyone, there is a potential possibility of that code invoking a > > > Destroy() on TheClass. I was wondering if there is a way to prevent > > > that. > > Declare the destructor of TheClass protected. > > > Michael, the way I have it now, TheClass is just an interface, not the > > > concrete implementation. So I guess I'm following that practice > > > already. > why not to refrence count 'TheClass'(e.g using boost::shared_ptr)? What does that solve (except introduce a lot of constraints in the use of TheClass). -- James Kanze (GABI Software) email:james.kanze@gmail.com Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34 |
|
![]() |
| Outils de la discussion | |
|
|