tightly coupled class design problem

Discussion in 'C++' started by Chocawok, Jan 27, 2006.

  1. Chocawok

    Chocawok Guest

    Some of the classes in my app are graphical.

    To encapsulate the graphical side of things I had created a class called
    "sprite" which holds a bit map and knows how to draw itself etc.



    The classes that are graphical contain a sprite object.



    MyClass

    {

    private:

    Sprite this_objects_sprite;

    }





    The sprite class requires a pointer to a "video surface". There is no way
    around this. The pointer is required for the construction and drawing of the
    sprite object.



    My problem is this:



    This design means that I have to pass the pointer to the video surface to
    myclass in its constructor, e.g.



    MyClass

    {

    private:

    Sprite this_objects_sprite;



    public:

    MyClass(VideoSurface* s)

    {

    this_objects_sprite = new Sprite(VideoSurface* s);

    ...

    ...

    }

    ....

    ....

    }



    Obviously this means all my graphical objects are tightly coupled to the
    graphics system I am using. Also obviously (I think) is that this is
    undesireable.



    I was thinking of maybe arranging things so that the sprite is not
    automatically instantiated in the container objects constructor.

    That is, I construct my object THEN call a function to construct the objects
    sprite, e.g.



    MyClass c = new MyClass();

    c.CreateSprite(VideoSurface* s);



    But then this raised other issues like, how do I handle what happens if i
    try to draw the object before creating its sprite.



    Any thoughts on this?

    Dean
     
    Chocawok, Jan 27, 2006
    #1
    1. Advertising

  2. Chocawok

    Mike Wahler Guest

    "Chocawok" <> wrote in message
    news:3NxCf.204940$...
    >
    >
    > Some of the classes in my app are graphical.
    >
    > To encapsulate the graphical side of things I had created a class called
    > "sprite" which holds a bit map and knows how to draw itself etc.
    >
    >
    >
    > The classes that are graphical contain a sprite object.
    >
    >
    >
    > MyClass
    >
    > {
    >
    > private:
    >
    > Sprite this_objects_sprite;
    >
    > }
    >
    >
    >
    >
    >
    > The sprite class requires a pointer to a "video surface". There is no way
    > around this. The pointer is required for the construction and drawing of
    > the sprite object.
    >
    >
    >
    > My problem is this:
    >
    >
    >
    > This design means that I have to pass the pointer to the video surface to
    > myclass in its constructor, e.g.
    >
    >
    >
    > MyClass
    >
    > {
    >
    > private:
    >
    > Sprite this_objects_sprite;
    >
    >
    >
    > public:
    >
    > MyClass(VideoSurface* s)
    >
    > {
    >
    > this_objects_sprite = new Sprite(VideoSurface* s);
    >
    > ...
    >
    > ...
    >
    > }
    >
    > ...
    >
    > ...
    >
    > }
    >
    >
    >
    > Obviously this means all my graphical objects are tightly coupled to the
    > graphics system I am using. Also obviously (I think) is that this is
    > undesireable.
    >
    >
    >
    > I was thinking of maybe arranging things so that the sprite is not
    > automatically instantiated in the container objects constructor.
    >
    > That is, I construct my object THEN call a function to construct the
    > objects sprite, e.g.
    >
    >
    >
    > MyClass c = new MyClass();
    >
    > c.CreateSprite(VideoSurface* s);
    >
    >
    >
    > But then this raised other issues like, how do I handle what happens if i
    > try to draw the object before creating its sprite.


    A simple approach could be:

    Continue to use a MyClass ctor (for all ctors) argument for your
    pointer, but always give it a default value (e.g. 0). Then
    have your draw functions check this pointer before using it.

    -Mike
     
    Mike Wahler, Jan 27, 2006
    #2
    1. Advertising

  3. Chocawok

    Jay Nabonne Guest

    On Fri, 27 Jan 2006 23:11:59 +0000, Chocawok wrote:

    >

    <snip>
    >
    > The classes that are graphical contain a sprite object.
    >
    >
    >
    > MyClass
    >
    > {
    >
    > private:
    >
    > Sprite this_objects_sprite;
    >
    > }
    >
    >
    >
    >
    >
    > The sprite class requires a pointer to a "video surface". There is no way
    > around this.
    > The pointer is required for the construction and drawing of the
    > sprite object.
    >
    >


    Question: when you say "There is no way around this.", do you mean that
    the current class design requires it, or that some underlying issue
    requires you to design the class this way? In other words, could you
    change the Sprite class to not take the VideoSurface at construction time
    but rather at draw time?

    >
    > My problem is this:
    >
    >
    >
    > This design means that I have to pass the pointer to the video surface to
    > myclass in its constructor, e.g.
    >
    >
    >
    > MyClass
    >
    > {
    >
    > private:
    >
    > Sprite this_objects_sprite;
    >
    >
    >
    > public:
    >
    > MyClass(VideoSurface* s)
    >
    > {
    >
    > this_objects_sprite = new Sprite(VideoSurface* s);


    This implies that "this_objects_sprite" is actually a "Sprite *" (not
    "Sprite").

    >
    > ...
    >
    > ...
    >
    > }
    >
    > ...
    >
    > ...
    >
    > }
    >
    >
    >
    > Obviously this means all my graphical objects are tightly coupled to the
    > graphics system I am using. Also obviously (I think) is that this is
    > undesireable.
    >
    >
    >
    > I was thinking of maybe arranging things so that the sprite is not
    > automatically instantiated in the container objects constructor.
    >
    > That is, I construct my object THEN call a function to construct the objects
    > sprite, e.g.
    >
    >
    >
    > MyClass c = new MyClass();
    >
    > c.CreateSprite(VideoSurface* s);
    >


    That would work. If you can change Sprite's semantics, you could also
    potentially still allow the construction of the sprite, but have an
    "attach" method to later connect it to a video surface.

    >
    >
    > But then this raised other issues like, how do I handle what happens if i
    > try to draw the object before creating its sprite.


    If the sprite member is a pointer, initialize it to 0 in the constructor
    and check. Additionally, if somehow the "draw" method knows about the
    video surface (e.g. it's passed as a parameter), you could create the
    sprite the first time you try to draw if it hasn't been created yet.

    - Jay
     
    Jay Nabonne, Jan 27, 2006
    #3
  4. Chocawok

    Daniel T. Guest

    In article <3NxCf.204940$>,
    "Chocawok" <> wrote:

    > Obviously this means all my graphical objects are tightly coupled to the
    > graphics system I am using. Also obviously (I think) is that this is
    > undesireable.


    The fact that you have a Sprite object contained within your MyClass
    object is what is making it tightly coupled to the graphics system. If
    you don't want that coupling, you need to abstract it out.

    If you can't change the Sprite class, then you will have to use an
    Adaptor.

    class Image {
    public:
    virtual ~Image() { }
    virtual void draw() = 0;
    };

    class SpriteAdaptor : public Image {
    Sprite _sprite;
    public:
    SpriteAdaptor( VideoSurface* s ): _sprite( s ) { }
    void draw() {
    _sprite.draw();
    }
    };

    class MyClass {
    Image* _image;
    public:
    MyClass( Image* i ): _image( i ) { assert( i ); }
    // call _image->draw() in some member-function
    };

    > I was thinking of maybe arranging things so that the sprite is not
    > automatically instantiated in the container objects constructor.
    >
    > That is, I construct my object THEN call a function to construct the objects
    > sprite, e.g.
    >
    >
    >
    > MyClass c = new MyClass();
    >
    > c.CreateSprite(VideoSurface* s);


    You can do that, but the coupling still exists in that case. MyClass has
    to include the Sprite header and possibly the VideoSurface header as
    well.
     
    Daniel T., Jan 28, 2006
    #4
  5. Chocawok

    Guest

    Chocawok wrote:
    > Some of the classes in my app are graphical.
    >
    > To encapsulate the graphical side of things I had created a class called
    > "sprite" which holds a bit map and knows how to draw itself etc.
    >
    >
    >
    > The classes that are graphical contain a sprite object.
    >
    >
    >
    > MyClass
    >
    > {
    >
    > private:
    >
    > Sprite this_objects_sprite;
    >
    > }
    >
    >
    >
    >
    >
    > The sprite class requires a pointer to a "video surface". There is no way
    > around this. The pointer is required for the construction and drawing of the
    > sprite object.
    >
    >
    >
    > My problem is this:
    >
    >
    >
    > This design means that I have to pass the pointer to the video surface to
    > myclass in its constructor, e.g.


    The broken part of this design is that Sprite "knows how to draw
    itself", and hence must take a pointer to a Surface. Sprite sounds like
    a value-semantic type to me, so what you need is a utility that draws
    Sprites given a Sprite and a Surface:

    class Sprite {...};

    class MyObject {
    Sprite d_sprite;
    //...
    public:
    const Sprite& sprite() const { return d_sprite; }
    };

    struct DrawUtil {
    static int draw(const Sprite& sprite, const Surface& surface);
    };
     
    , Jan 28, 2006
    #5
  6. Chocawok

    Daniel T. Guest

    The following is a message I came across on comp.lang.c++, it sounded
    like a good topic of discussion for comp.object as well, so I'm
    forwarding it here...

    ========== Begin Forwarded Message ==========
    From: "Chocawok" <>
    Subject: tightly coupled class design problem
    Date: Fri, Jan 27, 2006 6:11 PM

    Some of the classes in my app are graphical.

    To encapsulate the graphical side of things I had created a class called
    "sprite" which holds a bit map and knows how to draw itself etc.



    The classes that are graphical contain a sprite object.



    MyClass

    {

    private:

    Sprite this_objects_sprite;

    }





    The sprite class requires a pointer to a "video surface". There is no
    way
    around this. The pointer is required for the construction and drawing of
    the
    sprite object.



    My problem is this:



    This design means that I have to pass the pointer to the video surface
    to
    myclass in its constructor, e.g.



    MyClass

    {

    private:

    Sprite this_objects_sprite;



    public:

    MyClass(VideoSurface* s)

    {

    this_objects_sprite = new Sprite(VideoSurface*
    s);

    ...

    ...

    }

    ....

    ....

    }



    Obviously this means all my graphical objects are tightly coupled to the
    graphics system I am using. Also obviously (I think) is that this is
    undesireable.



    I was thinking of maybe arranging things so that the sprite is not
    automatically instantiated in the container objects constructor.

    That is, I construct my object THEN call a function to construct the
    objects
    sprite, e.g.



    MyClass c = new MyClass();

    c.CreateSprite(VideoSurface* s);



    But then this raised other issues like, how do I handle what happens if
    i
    try to draw the object before creating its sprite.



    Any thoughts on this?

    Dean
     
    Daniel T., Jan 28, 2006
    #6
  7. Chocawok

    Moonlit Guest

    Hi,

    Maybe you should abstract away the Graphics system as well as surfaces.

    For instance assume Sprite should, for performance reasons, create some
    surface in the graphics system (if that is possible for that graphics system
    on GDI based system it would just use system memory).


    For instance:
    ---------------------------------------------------------------------------------
    #include <list>
    using namespace std;

    // Generic Class that holds a piece of memory to prepare sprite on (could be
    located on the graphics card in system core or ....
    class GRGB;
    class GSprite;
    class GSurface
    {
    private:
    unsigned long Width,Height;
    public:
    GSurface( unsigned long Width, unsigned long Height ):
    Width( Width ),
    Height( Height )
    {
    }
    // Draw
    virtual void Prepare( unsigned long X, unsigned long Y, unsigned
    long Width, GRGB *BunchOfRgbValues ) = 0;

    };

    class GGDISurface : public GSurface
    {
    public:
    // New some memory from the heap on construction
    GGDISurface( unsigned long Width, unsigned long Height ):
    GSurface( Width, Height )

    {
    // Do stuff
    }
    // GDI Implementation draw on a piece of system memory, this is to
    prepare the sprite
    virtual void Prepare( unsigned long X, unsigned long Y, unsigned
    long Width, GRGB *BunchOfRgbValues )
    {
    }
    };

    class GDirectXSurface : public GSurface
    {
    public:
    // Get some memory from the graphics card on construction
    GDirectXSurface( unsigned long Width, unsigned long Height ):
    GSurface( Width, Height )
    {}
    // DirectX Implementation draw on the piece of memory on the
    graphics card
    virtual void Prepare( unsigned long X, unsigned long Y, unsigned
    long Width, GRGB *BunchOfRgbValues )
    {
    }
    };

    class GGraphicsSystem
    {
    private:
    std::list<GSprite*> SpriteList;
    public:
    virtual void AddSprite( GSprite *Sprite );
    virtual GSurface *CreateSurface( unsigned long Width, unsigned long
    Height ) = 0;
    };

    class GDirectXGraphicsSystem : public GGraphicsSystem
    {
    public:
    GDirectXSurface *CreateSurface( unsigned long Width, unsigned long
    Height )
    {
    }
    };

    class GSprite
    {
    private:
    GSurface *Surface;
    public:
    GSprite( GGraphicsSystem * GraphicsSystem )
    {
    Surface = GraphicsSystem->CreateSurface( 200, 200 );
    GRGB *Values;
    Surface->Prepare( 10, 10, 100, Values );
    }
    // Called by graphic system when sprites need to be redrawn (to keep it
    simple I assume the 'real' screen is also a surface
    void Draw( GSurface *ScreenSurface )
    {
    // Draw myself GSurface should also contain some (virtual) methods to
    draw GSurfaces on GSurfaces
    }
    };

    int main( int ArgC, char *ArgV[] )
    {
    return 0;
    }


    Regards, Ron AF Greve

    http://moonlit.xs4all.nl


    "Chocawok" <> wrote in message
    news:3NxCf.204940$...
    >
    >
    > Some of the classes in my app are graphical.
    >
    > To encapsulate the graphical side of things I had created a class called
    > "sprite" which holds a bit map and knows how to draw itself etc.
    >
    >
    >
    > The classes that are graphical contain a sprite object.
    >
    >
    >
    > MyClass
    >
    > {
    >
    > private:
    >
    > Sprite this_objects_sprite;
    >
    > }
    >
    >
    >
    >
    >
    > The sprite class requires a pointer to a "video surface". There is no way
    > around this. The pointer is required for the construction and drawing of
    > the sprite object.
    >
    >
    >
    > My problem is this:
    >
    >
    >
    > This design means that I have to pass the pointer to the video surface to
    > myclass in its constructor, e.g.
    >
    >
    >
    > MyClass
    >
    > {
    >
    > private:
    >
    > Sprite this_objects_sprite;
    >
    >
    >
    > public:
    >
    > MyClass(VideoSurface* s)
    >
    > {
    >
    > this_objects_sprite = new Sprite(VideoSurface* s);
    >
    > ...
    >
    > ...
    >
    > }
    >
    > ...
    >
    > ...
    >
    > }
    >
    >
    >
    > Obviously this means all my graphical objects are tightly coupled to the
    > graphics system I am using. Also obviously (I think) is that this is
    > undesireable.
    >
    >
    >
    > I was thinking of maybe arranging things so that the sprite is not
    > automatically instantiated in the container objects constructor.
    >
    > That is, I construct my object THEN call a function to construct the
    > objects sprite, e.g.
    >
    >
    >
    > MyClass c = new MyClass();
    >
    > c.CreateSprite(VideoSurface* s);
    >
    >
    >
    > But then this raised other issues like, how do I handle what happens if i
    > try to draw the object before creating its sprite.
    >
    >
    >
    > Any thoughts on this?
    >
    > Dean
    >
     
    Moonlit, Jan 28, 2006
    #7
  8. Chocawok

    Raghar Guest

    "Chocawok" <> wrote in
    news:3NxCf.204940$:


    >
    > Some of the classes in my app are graphical.


    Interesting, how could such ugly problem happen to them?

    >
    > To encapsulate the graphical side of things I had created a
    > class called "sprite" which holds a bit map and knows how to
    > draw itself etc.
    >


    It knows? And could it give that information to something that
    is able to use it with knowledge how to talk to the graphic
    device/s?

    >
    > The classes that are graphical contain a sprite object.


    I hope quad/oct tree countains just pointers/references to
    "sprite" / image/ managedImage objects.

    > The sprite class requires a pointer to a "video surface".

    There
    > is no way around this. The pointer is required for the
    > construction


    Incorrect.

    > and drawing of the sprite object.


    If pointer to "drawing surface" / OGL is in different class,
    that accepts "sprite" objects, then it's in the only place
    where it need to be, in you case.


    > This design means


    Bad design. Imagine what would happen if that pointer would be
    volatile.

    > .........
    > But then this raised other issues like, how do I handle what
    > happens if i try to draw the object before creating its

    sprite.
    >


    You have two possibilities. 1. Nothing. 2. Null pointer
    exception.
     
    Raghar, Jan 28, 2006
    #8
  9. Chocawok

    Guest

    Chocawok wrote:
    > Some of the classes in my app are graphical.
    >
    > To encapsulate the graphical side of things I had created a class called
    > "sprite" which holds a bit map and knows how to draw itself etc.
    >
    > > MyClass


    It seems that if some of your classes are inherently graphical, and
    others are not, you can express this by synthesizing the types you need
    using multiple inheritance:

    class WithSprite : public MyClass, public Sprite
    {
    } ;

    class WithoutSprite : public MyClass
    {
    } ;

    Virtual functions (and perhaps another class) will allow you to deal
    with differences between classes that are graphical and classes that
    are not.

    But again, all of this depends on your big picture.

    -Le Chaud Lapin-
     
    , Jan 28, 2006
    #9
  10. Chocawok

    Chocawok Guest

    I think I have come to a decision.

    I think the best solution is to have a Sprite class which handles the
    graphics and drawing of itself.

    BUT, and this is the new bit, construct the Sprite outside of the container
    object. This way the containing object doesn't need to know ANY details of
    how the sprite is constructed or how it draws iself.

    e.g.

    Sprite
    {
    bitmap i;
    VideoSurface* drawingdestination;
    Sprite(VideoSurface* s, bitmap b) { drawingdestination = s; i = b}
    Draw();
    }

    MyClass
    {
    Sprite* s;
    void MyClass();
    void AttachSprite(Sprite* s) {this.s = s};
    void Draw() {s.draw();}
    }

    main()
    {
    myobj = new MyClass();
    myobj.AttachSprite(new Sprite(videoram, image));
    myobj.Draw();
    }

    This means all the graphics details (DirectX or OpenGL or GDI etc) stay in
    the one class, providing nice encapsulation.

    I think i was getting confused, because I was trying to abstract away the
    very fact that my objects have a graphical side to them. Which didn't make
    any sense, because they are graphical in nature.

    thanks very much for all your ideas.

    Dean
     
    Chocawok, Jan 28, 2006
    #10
  11. Chocawok

    I V Guest

    Making the Sprite responsible for knowing what surface to draw itself
    on looks like a good decision. However:

    Chocawok wrote:
    > MyClass
    > {
    > Sprite* s;
    > void MyClass();
    > void AttachSprite(Sprite* s) {this.s = s};
    > void Draw() {s.draw();}


    What happens if you call Draw on a MyClass object before you've called
    AttachSprite? At the very least, MyClass::Draw needs to make sure it
    has a valid sprite and take appropriate action (perhaps throw an
    exception) if not.

    However, that's not ideal, because this problem would only show up at
    run time, and so you might miss it in your tests. If Draw is essential
    to the function of MyClass, then a MyClass object is conceptually
    incomplete without a Sprite, and that's a problem. All objects should
    have all the information they need to function straight after they have
    been constructed. So why not:

    class MyClass
    {
    Sprite* sprite_;
    public:
    MyClass(Sprite* s)
    : sprite_(s)
    { }

    void draw()
    { s->draw(); }
    };

    This means you have to delay constructing the MyClass objects until you
    can create the DrawingSurface and the Sprites; maybe that is difficult
    for some reason, in which case you might have to go with your
    AttachSprite method, but you should probably try and avoid that if you
    can.

    > I think i was getting confused, because I was trying to abstract away the
    > very fact that my objects have a graphical side to them. Which didn't make
    > any sense, because they are graphical in nature.


    Yes, that sounds right.
     
    I V, Jan 28, 2006
    #11
  12. Chocawok

    Guest

    , Jan 28, 2006
    #12
  13. Chocawok

    Chocawok Guest

    > run time, and so you might miss it in your tests. If Draw is essential
    > to the function of MyClass, then a MyClass object is conceptually
    > incomplete without a Sprite, and that's a problem. All objects should
    > have all the information they need to function straight after they have
    > been constructed. So why not:
    >
    > class MyClass
    > {
    > Sprite* sprite_;
    > public:
    > MyClass(Sprite* s)
    > : sprite_(s)
    > { }
    >
    > void draw()
    > { s->draw(); }
    > };
    >
    > This means you have to delay constructing the MyClass objects until you
    > can create the DrawingSurface and the Sprites; maybe that is difficult
    > for some reason, in which case you might have to go with your
    > AttachSprite method, but you should probably try and avoid that if you


    I see your points and your right. Calling the constructor of MyClass with
    the Sprite as a parameter seems the way to go.

    Thanks for that.

    BTW, I'm not familiar with the syntax you've used in part of your code. I
    presume:

    MyClass(Sprite* s)
    : sprite_(s)
    { }


    does the same thing as:

    MyClass(Sprite* s) { sprite_ = s};


    And one final thing, I notice you use an underscore in the sprite variable
    name, "sprite_" and somewhere else in the thread someone used "_sprite". Is
    there any convention being used here, and if so, what is it?

    Thanks

    Dean
     
    Chocawok, Jan 29, 2006
    #13
  14. Chocawok

    JustBoo Guest

    On Sun, 29 Jan 2006 00:12:36 GMT, "Chocawok" <>
    wrote:

    >BTW, I'm not familiar with the syntax you've used in part of your code. I
    >presume:
    >
    > MyClass(Sprite* s)
    > : sprite_(s)
    > { }
    >
    >does the same thing as:
    >
    >MyClass(Sprite* s) { sprite_ = s};


    Grab any good current book on C++ and read about the "Initialization
    List."

    Also the FAQ has a pretty bad article about it.
    http://www.parashift.com/c -faq-lite/ctors.html#faq-10.6

    Much Much Much Better Here:
    http://www.goingware.com/tips/parameters/membervars.html

    HTH - Good Luck
     
    JustBoo, Jan 29, 2006
    #14
  15. Chocawok

    I V Guest

    Chocawok wrote:
    > BTW, I'm not familiar with the syntax you've used in part of your code. I
    > presume:
    >
    > MyClass(Sprite* s)
    > : sprite_(s)
    > { }
    >
    > does the same thing as:
    >
    > MyClass(Sprite* s) { sprite_ = s};


    Pretty much. There's a slightly subtle difference which is only likely
    to be important if the member variable is itself an instance of a
    class. Doing:

    class MyClass
    {
    OtherClass other_;
    public:
    MyClass(OtherClass o)
    {
    other_ = o;
    }
    };

    Calls the default constructor of OtherClass to create other_ , and then
    the assignment operator to set other_ to o

    Wheras:

    MyClass(OtherClass o)
    : other_(o)
    { }

    doesn't call the default constructor of OtherClass, but calls the copy
    constructor to make other_ be a copy of o. This may be significant if
    the default constructor takes a long time, or if OtherClass doesn't
    _have_ a default constructor. It's probably a good idea to use the
    initializer list, as that makes it clear to people reading the source
    that you are just initializing your members, rather than doing anything
    else.

    > And one final thing, I notice you use an underscore in the sprite variable
    > name, "sprite_" and somewhere else in the thread someone used "_sprite". Is
    > there any convention being used here, and if so, what is it?


    It's a moderately common convention to mark member variables with an
    underscore, either at the beginning or the end; some people use a
    naming convention like m_member instead.
     
    I V, Jan 29, 2006
    #15
  16. * JustBoo:
    > On Sun, 29 Jan 2006 00:12:36 GMT, "Chocawok" <>
    > wrote:
    >
    > >BTW, I'm not familiar with the syntax you've used in part of your code. I
    > >presume:
    > >
    > > MyClass(Sprite* s)
    > > : sprite_(s)
    > > { }
    > >
    > >does the same thing as:
    > >
    > >MyClass(Sprite* s) { sprite_ = s};

    >
    > Grab any good current book on C++ and read about the "Initialization
    > List."
    >
    > Also the FAQ has a pretty bad article about it.
    > http://www.parashift.com/c -faq-lite/ctors.html#faq-10.6


    What do you think is "bad"?


    > Much Much Much Better Here:
    > http://www.goingware.com/tips/parameters/membervars.html


    This article is sometimes misleading and incorrect.

    Let's start with the very first sentence:

    "Member variables must be initialized in the constructor's
    initialization list."

    That's false.

    First part of sentence 2:

    "Smart pointer members minimize dependencies"

    That's generally false.

    Second part of sentence 2:

    "while allowing exception safety."

    That's misleading: smart pointers don't just allow exception safety, and
    their exception safety is not a secondary consideration.

    Next follows a sub-heading:

    "Minimize Dependencies by Storing Members as Pointers"

    That's not bad advice, but there is no discussion of the trade-off
    involved, notably efficiency.

    First paragraph that section then says nothing remarkable, but is
    followed by example code that won't compile. It's nothing dramatic (a
    missing semicolon) but shows lack of attention to detail.

    Then we get to a sub-sub-heading:

    "The Initialization List"

    and the first sentence of that section

    "Note that it is terribly important that you initialize pointer
    members (actually any member) of your objects in the constructor's
    initialization list."

    which is simply false, again. Some times (the FAQ lists some
    situations) it's terribly important that you don't.

    Third sentence of that section:

    "If you don't always need to have a pointer member in existence during
    the lifetime of your object, you may choose to initialize it to nil"

    'nil' is Pascal terminology, there's no such thing in C++ (the author
    probably means 0).

    Ah, well, I'm not going to trash that article. As a motivational
    article it's great. But as a technical resource it's not up to the
    FAQ's standard of quality -- not even 10% in that direction.

    --
    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?
     
    Alf P. Steinbach, Jan 29, 2006
    #16
  17. Chocawok

    JustBoo Guest

    On Sun, 29 Jan 2006 02:04:15 GMT, (Alf P. Steinbach)
    wrote:
    >* JustBoo:
    >> Also the FAQ has a pretty bad article about it.
    >> http://www.parashift.com/c -faq-lite/ctors.html#faq-10.6
    >> Much Much Much Better Here:
    >> http://www.goingware.com/tips/parameters/membervars.html

    >
    >This article is sometimes misleading and incorrect.

    [snipped commentary]

    Thank you Alf, for all that work.

    Note I included *both* links. I find comparative analyses to be an
    invaluable tool for a software engineer.

    Also note, I now realize I should have tempered *my commentary* about
    the articles themselves.

    I have to say thought, I'm glad we're all just commentators on usenet
    and not editors. :) <==

    Success is not final, failure is not fatal: it is the courage to
    continue that counts. - Winston Churchill
     
    JustBoo, Jan 29, 2006
    #17
  18. Chocawok

    H. S. Lahman Guest

    Responding to Daniel T. and Whoever...

    > The following is a message I came across on comp.lang.c++, it sounded
    > like a good topic of discussion for comp.object as well, so I'm
    > forwarding it here...
    >
    > ========== Begin Forwarded Message ==========
    > From: "Chocawok" <>
    > Subject: tightly coupled class design problem
    > Date: Fri, Jan 27, 2006 6:11 PM
    >
    > Some of the classes in my app are graphical.
    >
    > To encapsulate the graphical side of things I had created a class called
    > "sprite" which holds a bit map and knows how to draw itself etc.
    >
    >
    >
    > The classes that are graphical contain a sprite object.
    >
    >
    >
    > MyClass
    >
    > {
    >
    > private:
    >
    > Sprite this_objects_sprite;
    >
    > }



    Given that C++ has reference pointers, I am afraid I not keen on this
    and your first sentence. The sprite is a graphical representation /of/
    whatever entity MyClass abstracts from the problem space. That
    qualifies the sprite as a distinct conceptual entity that is a peer of
    MyClass.

    So it shouldn't be part of the implementation of MyClass and one needs a
    reference based relationship implementation for it. If one thinks of it
    as a peer via

    1 corresponds to 1
    [MyClass] --------------------- [Sprite]

    then

    Sprite* this_objects_sprite;

    just implements the peer relationship. That segues to...

    > The sprite class requires a pointer to a "video surface". There is no
    > way
    > around this. The pointer is required for the construction and drawing of
    > the
    > sprite object.


    Fine. All the more reason to make Sprite a peer object.

    > My problem is this:
    >
    >
    >
    > This design means that I have to pass the pointer to the video surface
    > to
    > myclass in its constructor, e.g.
    >
    >
    >
    > MyClass
    >
    > {
    >
    > private:
    >
    > Sprite this_objects_sprite;
    >
    >
    >
    > public:
    >
    > MyClass(VideoSurface* s)
    >
    > {
    >
    > this_objects_sprite = new Sprite(VideoSurface*
    > s);
    >
    > ...
    >
    > ...
    >
    > }
    >
    > ...
    >
    > ...
    >
    > }
    >
    >
    >
    > Obviously this means all my graphical objects are tightly coupled to the
    > graphics system I am using. Also obviously (I think) is that this is
    > undesireable.


    I don't see a problem here so long as this_objects_sprite is just
    instantiating a relationship. As you indicate above, that relationship
    is fixed in the problem space. Therefore it must be established somehow.

    If the relationship is fixed throughout the like of MyClass, then
    instantiating the reference via the MyClass constructor is fine. If the
    context can change during MyClass' life cycle, then one would need a
    set_sprite method to re-instantiate the relationship properly when the
    context changes.

    [Note that even if it is fixed for life now, one can add set_sprite
    later if things change with minimal hassle because it /is/ just a
    relationship implementation rather than part of the MyClass
    implementation. This becomes even more important if one later decides
    that [Sprite] needs to be accessed by other objects than {MyClass].
    Keep this in mind in the discussion of relationship path navigation below.]

    However, the key issue is that relationship navigation is orthogonal to
    class semantics. MyClass may or may not need to collaborate with the
    Sprite. Assuming MyClass has some other role in solving the customer's
    problem, Sprite will probably be accessed by some other object that
    understands graphical issues like when the display needs to be rendered
    or updated. So it is likely that Sprite will be accessed /through/
    MyClass by that object and MyClass won't know anything about that, as in:

    [Renderer]
    | 1
    | displayed by
    |
    | R1
    |
    | *
    [MyClass]
    | 1
    | corresponds to
    |
    | R2
    |
    | 1 * constrains 1
    [Sprite] ------------------------ [VideoSurface]
    R3

    To do the display Renderer needs the the information from [Sprite] so it
    navigates R1 -> R2 to get it. In doing so MyClass is just a way point
    in addressing the collaboration to the right [Sprite] instance. Since
    Renderer's collaboration is peer-to-peer with Sprite, it doesn't need to
    know and shouldn't know anything about the semantics of MyClass (other
    than the implementation of the relationship path).

    Similarly, if Renderer needs to collaborate with the relevant
    VideoSurface, then it also needs to navigate R1 -> R2 -> R3. But in
    that peer-to-peer collaboration Renderer needs to know nothing about
    MyClass or Sprite. More important to your concern here is that MyClass
    doesn't need to know anything about that collaboration or the semantics
    of [VideoSurface]. It's only knowledge of [VideoSurface] is the Class
    type for C++ to properly type the reference pointer that implements the
    relationship.

    [Automatic code generators for OOA models don't even need to know the
    class. Typically they instantiate relationships with Object*
    references. The only place the class type /needs/ to be defined is in
    Renderer so it can access properties. The code generator can cast that
    safely because it knows from the UML model exactly what the class /must/
    be when it write the [Renderer] code.]

    So if all one is doing is instantiating a relationship, then there is no
    heavy duty coupling between [VideoSurface] and any class along the path
    except [Renderer]. (Renderer is necessarily coupled because it is doing
    peer-to-peer collaboration with [VideoSurface].) In fact, I believe
    that the main role of relationships in the OO paradigm is to provide a
    context-independent mechanism to /ensure/ decoupling except among
    collaborating peers. [Almost as important is the management of access
    to state variables (attributes).]


    *************
    There is nothing wrong with me that could
    not be cured by a capful of Drano.

    H. S. Lahman

    Pathfinder Solutions -- Put MDA to Work
    http://www.pathfindermda.com
    blog: http://pathfinderpeople.blogs.com/hslahman
    (888)OOA-PATH
     
    H. S. Lahman, Jan 29, 2006
    #18
  19. Chocawok

    Daniel T. Guest

    In article <XIRCf.207018$>,
    "Chocawok" <> wrote:

    > I think I have come to a decision.
    >
    > I think the best solution is to have a Sprite class which handles the
    > graphics and drawing of itself.
    >
    > BUT, and this is the new bit, construct the Sprite outside of the container
    > object. This way the containing object doesn't need to know ANY details of
    > how the sprite is constructed or how it draws iself.
    >
    > e.g.
    >
    > Sprite
    > {
    > bitmap i;
    > VideoSurface* drawingdestination;
    > Sprite(VideoSurface* s, bitmap b) { drawingdestination = s; i = b}
    > Draw();
    > }
    >
    > MyClass
    > {
    > Sprite* s;
    > void MyClass();
    > void AttachSprite(Sprite* s) {this.s = s};
    > void Draw() {s.draw();}
    > }
    >
    > main()
    > {
    > myobj = new MyClass();
    > myobj.AttachSprite(new Sprite(videoram, image));
    > myobj.Draw();
    > }
    >
    > This means all the graphics details (DirectX or OpenGL or GDI etc) stay in
    > the one class, providing nice encapsulation.


    Not quite, but good enough. Presumably, there will be some graphics
    details in sprite.h and myclass.cpp must include sprite.h to compile
    which means that some of the details will leak into myclass.cpp (at the
    very least, if those details change, myclass.cpp will have to be
    recompiled.)

    This isn't necessarily a bad thing, but it might be better to have an
    abstract "Drawable" class that Sprite inherits from and MyClass
    contains.

    --
    Magic depends on tradition and belief. It does not welcome observation,
    nor does it profit by experiment. On the other hand, science is based
    on experience; it is open to correction by observation and experiment.
     
    Daniel T., Jan 29, 2006
    #19
  20. Daniel T. wrote:
    > The following is a message I came across on comp.lang.c++, it sounded
    > like a good topic of discussion for comp.object as well, so I'm
    > forwarding it here...
    >
    > ========== Begin Forwarded Message ==========
    > From: "Chocawok" <>
    > Subject: tightly coupled class design problem
    > Date: Fri, Jan 27, 2006 6:11 PM
    >
    > Some of the classes in my app are graphical.
    >
    > To encapsulate the graphical side of things I had created a class called
    > "sprite" which holds a bit map and knows how to draw itself etc.
    >
    >
    >
    > The classes that are graphical contain a sprite object.
    >
    >
    >
    > MyClass
    >
    > {
    >
    > private:
    >
    > Sprite this_objects_sprite;
    >
    > }
    >
    >
    >
    >
    >
    > The sprite class requires a pointer to a "video surface". There is no
    > way
    > around this. The pointer is required for the construction and drawing of
    > the
    > sprite object.
    >
    >
    >
    > My problem is this:
    >
    >
    >
    > This design means that I have to pass the pointer to the video surface
    > to
    > myclass in its constructor, e.g.
    >
    >
    >
    > MyClass
    >
    > {
    >
    > private:
    >
    > Sprite this_objects_sprite;
    >
    >
    >
    > public:
    >
    > MyClass(VideoSurface* s)
    >
    > {
    >
    > this_objects_sprite = new Sprite(VideoSurface*
    > s);
    >
    > ...
    >
    > ...
    >
    > }
    >
    > ...
    >
    > ...
    >
    > }
    >
    >
    >
    > Obviously this means all my graphical objects are tightly coupled to the
    > graphics system I am using. Also obviously (I think) is that this is
    > undesireable.
    >
    >
    >
    > I was thinking of maybe arranging things so that the sprite is not
    > automatically instantiated in the container objects constructor.
    >
    > That is, I construct my object THEN call a function to construct the
    > objects
    > sprite, e.g.
    >
    >
    >
    > MyClass c = new MyClass();
    >
    > c.CreateSprite(VideoSurface* s);
    >
    >
    >
    > But then this raised other issues like, how do I handle what happens if
    > i
    > try to draw the object before creating its sprite.
    >
    >
    >
    > Any thoughts on this?
    >
    > Dean


    sounds virtually exacltly the same scenario described in Design
    Patterns (Gamma et al), for the application of the 'abstract factory'
    patterm....i.e. basically you abstract away your graphics systems
    behind a factory and a family of wrapped.

    Have you got GoF?

    I could ramble away like an idiot but best look there. p87.
     
    Mark Nicholls, Jan 30, 2006
    #20
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. jersie0
    Replies:
    6
    Views:
    19,511
    Toby A Inkster
    Nov 16, 2003
  2. Replies:
    2
    Views:
    7,885
    Marcus Harnisch
    Oct 30, 2006
  3. wallge
    Replies:
    2
    Views:
    561
    Derek Simmons
    Jan 5, 2007
  4. Jim Langston
    Replies:
    5
    Views:
    356
    Jim Langston
    Sep 6, 2007
  5. Cal Who

    a:hover and ahover are coupled

    Cal Who, Jan 17, 2010, in forum: ASP .Net
    Replies:
    10
    Views:
    837
    Cal Who
    Jan 19, 2010
Loading...

Share This Page