Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c++ > #11525 > unrolled thread

How can I remove dynamic_cast and if statements from this code snippet?

Started byChris Stankevitz <chrisstankevitz@gmail.com>
First post2011-11-16 10:37 -0800
Last post2011-11-18 09:23 -0800
Articles 20 on this page of 41 — 11 participants

Back to article view | Back to comp.lang.c++


Contents

  How can I remove dynamic_cast and if statements from this code snippet? Chris Stankevitz <chrisstankevitz@gmail.com> - 2011-11-16 10:37 -0800
    Re: How can I remove dynamic_cast and if statements from this code snippet? Ian Collins <ian-news@hotmail.com> - 2011-11-17 07:52 +1300
      Re: How can I remove dynamic_cast and if statements from this code snippet? Chris Stankevitz <chrisstankevitz@gmail.com> - 2011-11-16 11:14 -0800
        Re: How can I remove dynamic_cast and if statements from this code snippet? red floyd <no.spam.here@its.invalid> - 2011-11-16 12:03 -0800
          Re: How can I remove dynamic_cast and if statements from this code snippet? Chris Stankevitz <chrisstankevitz@gmail.com> - 2011-11-16 13:28 -0800
            Re: How can I remove dynamic_cast and if statements from this code snippet? Leigh Johnston <leigh@i42.co.uk> - 2011-11-16 21:39 +0000
              Re: How can I remove dynamic_cast and if statements from this code snippet? Leigh Johnston <leigh@i42.co.uk> - 2011-11-16 21:40 +0000
                Re: How can I remove dynamic_cast and if statements from this code snippet? Leigh Johnston <leigh@i42.co.uk> - 2011-11-16 21:43 +0000
                  Re: How can I remove dynamic_cast and if statements from this code snippet? Leigh Johnston <leigh@i42.co.uk> - 2011-11-16 21:45 +0000
              Re: How can I remove dynamic_cast and if statements from this code snippet? Chris Stankevitz <chrisstankevitz@gmail.com> - 2011-11-16 13:46 -0800
                Re: How can I remove dynamic_cast and if statements from this code snippet? Leigh Johnston <leigh@i42.co.uk> - 2011-11-16 21:49 +0000
        Re: How can I remove dynamic_cast and if statements from this code snippet? Leigh Johnston <leigh@i42.co.uk> - 2011-11-16 20:35 +0000
          Re: How can I remove dynamic_cast and if statements from this code snippet? Chris Stankevitz <chrisstankevitz@gmail.com> - 2011-11-16 13:38 -0800
        Re: How can I remove dynamic_cast and if statements from this code snippet? Ian Collins <ian-news@hotmail.com> - 2011-11-17 10:37 +1300
          Re: How can I remove dynamic_cast and if statements from this code snippet? Chris Stankevitz <chrisstankevitz@gmail.com> - 2011-11-16 13:41 -0800
            Re: How can I remove dynamic_cast and if statements from this code snippet? Ian Collins <ian-news@hotmail.com> - 2011-11-17 10:56 +1300
              Re: How can I remove dynamic_cast and if statements from this code snippet? Chris Stankevitz <chrisstankevitz@gmail.com> - 2011-11-16 14:03 -0800
                Re: How can I remove dynamic_cast and if statements from this code snippet? Ian Collins <ian-news@hotmail.com> - 2011-11-17 11:12 +1300
                  Re: How can I remove dynamic_cast and if statements from this code snippet? Chris Stankevitz <chrisstankevitz@gmail.com> - 2011-11-16 15:20 -0800
                    Re: How can I remove dynamic_cast and if statements from this code snippet? Werner <werasm@gmail.com> - 2011-11-16 23:39 -0800
                      Re: How can I remove dynamic_cast and if statements from this code snippet? Goran <goran.pusic@gmail.com> - 2011-11-17 05:42 -0800
                        Re: How can I remove dynamic_cast and if statements from this code snippet? Chris Stankevitz <chrisstankevitz@gmail.com> - 2011-11-17 10:37 -0800
                          Re: How can I remove dynamic_cast and if statements from this code snippet? Werner <werasm@gmail.com> - 2011-11-17 23:23 -0800
                            Re: How can I remove dynamic_cast and if statements from this code snippet? Goran <goran.pusic@gmail.com> - 2011-11-18 01:46 -0800
                          Re: How can I remove dynamic_cast and if statements from this code snippet? Goran <goran.pusic@gmail.com> - 2011-11-18 01:25 -0800
                        Re: How can I remove dynamic_cast and if statements from this code snippet? Werner <werasm@gmail.com> - 2011-11-17 23:28 -0800
                      Re: How can I remove dynamic_cast and if statements from this code snippet? Chris Stankevitz <chrisstankevitz@gmail.com> - 2011-11-17 10:27 -0800
                    Re: How can I remove dynamic_cast and if statements from this code snippet? Goran <goran.pusic@gmail.com> - 2011-11-17 05:17 -0800
                      Re: How can I remove dynamic_cast and if statements from this code snippet? Chris Stankevitz <chrisstankevitz@gmail.com> - 2011-11-17 10:35 -0800
    Re: How can I remove dynamic_cast and if statements from this code snippet? Francesco <xtrigger303@gmail.com> - 2011-11-17 01:56 -0800
      Re: How can I remove dynamic_cast and if statements from this code snippet? Chris Stankevitz <chrisstankevitz@gmail.com> - 2011-11-17 10:31 -0800
    Re: How can I remove dynamic_cast and if statements from this code snippet? <address_is@invalid.invalid> - 2011-11-17 19:21 +0000
      Re: How can I remove dynamic_cast and if statements from this code snippet? Leigh Johnston <leigh@i42.co.uk> - 2011-11-17 19:33 +0000
      Re: How can I remove dynamic_cast and if statements from this code snippet? Chris Stankevitz <chrisstankevitz@gmail.com> - 2011-11-17 14:09 -0800
        Re: How can I remove dynamic_cast and if statements from this code snippet? Werner <werasm@gmail.com> - 2011-11-17 23:30 -0800
          Re: How can I remove dynamic_cast and if statements from this code snippet? Bart v Ingen Schenau <bart@ingen.ddns.info> - 2011-11-18 14:45 +0100
      Re: How can I remove dynamic_cast and if statements from this code snippet? Goran <goran.pusic@gmail.com> - 2011-11-18 02:58 -0800
        Re: How can I remove dynamic_cast and if statements from this code snippet? Tobias Müller <troplin@bluewin.ch> - 2011-11-18 16:56 +0000
          Re: How can I remove dynamic_cast and if statements from this code snippet? Chris Stankevitz <chrisstankevitz@gmail.com> - 2011-11-18 17:27 -0800
      Re: How can I remove dynamic_cast and if statements from this code snippet? Goran <goran.pusic@gmail.com> - 2011-11-18 01:29 -0800
    Re: How can I remove dynamic_cast and if statements from this code snippet? Noah Roberts <roberts.noah@gmail.com> - 2011-11-18 09:23 -0800

Page 1 of 3  [1] 2 3  Next page →


#11525 — How can I remove dynamic_cast and if statements from this code snippet?

FromChris Stankevitz <chrisstankevitz@gmail.com>
Date2011-11-16 10:37 -0800
SubjectHow can I remove dynamic_cast and if statements from this code snippet?
Message-ID<f5bb1b81-4daf-4b54-b7f2-d601f03ab1a2@y42g2000yqh.googlegroups.com>
Hello,

I would like to remove the "dynamic_cast" and "if" statements from the
code below.  I believe some people would describe this as making the
code "polymorphic".  Can you recommend a way to do this without
modifying the original classes in "Library A"?

My intention is to create an "XML Writer" class(es) for shapes without
putting "XML code" in the base classes.  I plan to use a similar
pattern for drawing and other tasks my application has to perform on
Shape objects.

Thank you,

Chris

// Library A
struct Shape { virtual ~Shape() {} };
struct Circle : public Shape { float radius; };
struct Square : public Shape { float edge; };

// Library B
#include <iostream>

class XmlWriter
{
  static void write(Shape* shape)
  {
    if (Circle* circle = dynamic_cast<Circle*>(shape))
    {
      std::cout << "<Circle Radius=" << circle->radius << "/>";
    }
    else if (Square* square = dynamic_cast<Square*>(shape))
    {
      std::cout << "<Square Edge=" << square->edge << "/>";
    }
  }
};

[toc] | [next] | [standalone]


#11526

FromIan Collins <ian-news@hotmail.com>
Date2011-11-17 07:52 +1300
Message-ID<9iif3pFi5oU11@mid.individual.net>
In reply to#11525
On 11/17/11 07:37 AM, Chris Stankevitz wrote:
> Hello,
>
> I would like to remove the "dynamic_cast" and "if" statements from the
> code below.  I believe some people would describe this as making the
> code "polymorphic".  Can you recommend a way to do this without
> modifying the original classes in "Library A"?
>
> My intention is to create an "XML Writer" class(es) for shapes without
> putting "XML code" in the base classes.  I plan to use a similar
> pattern for drawing and other tasks my application has to perform on
> Shape objects.
>
> Thank you,
>
> Chris
>
> // Library A
> struct Shape { virtual ~Shape() {} };
> struct Circle : public Shape { float radius; };
> struct Square : public Shape { float edge; };
>
> // Library B
> #include<iostream>
>
> class XmlWriter
> {
>    static void write(Shape* shape)
>    {
>      if (Circle* circle = dynamic_cast<Circle*>(shape))
>      {
>        std::cout<<  "<Circle Radius="<<  circle->radius<<  "/>";
>      }
>      else if (Square* square = dynamic_cast<Square*>(shape))
>      {
>        std::cout<<  "<Square Edge="<<  square->edge<<  "/>";
>      }
>    }
> };

Something like:

struct Shape {
   virtual void write() = 0;
};
struct Circle : public Shape {
   float radius;
   void write()
   {
     std::cout<<  "<Circle Radius="<<  circle->radius<<  "/>";
   }
};

struct Square : public Shape {
   float edge;
   void write()
   {
     std::cout<<  "<Square Edge="<<  square->edge<<  "/>";
   }
};

class XmlWriter
{
   static void write(Shape* shape)
   {
     shape->write();
   }
};

-- 
Ian Collins

[toc] | [prev] | [next] | [standalone]


#11528

FromChris Stankevitz <chrisstankevitz@gmail.com>
Date2011-11-16 11:14 -0800
Message-ID<cb08fb25-4306-466d-88bb-563752af7160@a16g2000yqk.googlegroups.com>
In reply to#11526
On Nov 16, 10:52 am, Ian Collins <ian-n...@hotmail.com> wrote:
> Something like:
>
> struct Shape {
>    virtual void write() = 0;};

Ian,

I prefer/require a solution in which the shapes themselves are not
writing out XML -- I want the XML related code restricted to the
"XmlWriter" class in "Library B".  This appears to be an overly
draconian requirement in this simple example, but should make more
sense if you consider adding something like a "drawing" or "network"
class that would introduce dependencies on drawing or socket code.

I want drawing/xml/socket code relegated to "Library B" without
compile or link dependencies in "Library A".

Thank you,

Chris

[toc] | [prev] | [next] | [standalone]


#11530

Fromred floyd <no.spam.here@its.invalid>
Date2011-11-16 12:03 -0800
Message-ID<ja14uv$qub$1@dont-email.me>
In reply to#11528
On 11/16/2011 11:14 AM, Chris Stankevitz wrote:
> On Nov 16, 10:52 am, Ian Collins<ian-n...@hotmail.com>  wrote:
>> Something like:
>>
>> struct Shape {
>>     virtual void write() = 0;};
>
> Ian,
>
> I prefer/require a solution in which the shapes themselves are not
> writing out XML -- I want the XML related code restricted to the
> "XmlWriter" class in "Library B".  This appears to be an overly
> draconian requirement in this simple example, but should make more
> sense if you consider adding something like a "drawing" or "network"
> class that would introduce dependencies on drawing or socket code.
>
> I want drawing/xml/socket code relegated to "Library B" without
> compile or link dependencies in "Library A".
>


You are somewhat correct here.  Have the "write" function return
a string which the XML code can display.  By divorcing the I/O from
the representation return, you're more general anyways.

BTW, what book are you reading?  This fragment/problem is actually
one of the canonical OOP examples.

class Shape {
public:
//...
virtual std::string as_string()  = 0;
}

class Square {
//...
std::string as_string() { return "Edge..." };
}

class

[toc] | [prev] | [next] | [standalone]


#11532

FromChris Stankevitz <chrisstankevitz@gmail.com>
Date2011-11-16 13:28 -0800
Message-ID<8b319949-9e54-441c-9f64-3b769c4926b2@h31g2000pro.googlegroups.com>
In reply to#11530
On Nov 16, 12:03 pm, red floyd <no.spam.h...@its.invalid> wrote:
> You are somewhat correct here.  Have the "write" function return
> a string which the XML code can display.  By divorcing the I/O from
> the representation return, you're more general anyways.

Red,

Thank you for your reply.  I believe you have attempted to solve my
problem by modifying the original shapes to return their "XML
components" as strings.

Unfortunately this is not what I am interested in because it does not
scale to what I really want to do.  Instead of writing a long-winded
response that might not come across correctly, allow me to change my
original question to use drawing instead of string writing:

===

Is it possible in C++ to modify "Library B" below to eliminate the
dynamic_cast and switch statements, while at the same time not doing
any of the following:
- Do not use DeviceContext in "Library A"
- Do not put drawing code in "Library A"
- Do not put the concept of drawing into "Library A" including adding
a class Shape::GetPixelsToDraw

My goal is to
a) not put any reference to drawing into Library A
b) not use dynamic_cast or switch/if blocks in Library B

The answer might be something like "use factories" or "use template"
or "this is not possible in c++".

Thank you,

Chris


// Library A
struct Shape { virtual ~Shape() {} };
struct Circle : public Shape { float radius; };
struct Square : public Shape { float edge; };

// Library B

#include <cmath>
struct DeviceContext { void FillPixel(int PixelX, int PixelY) {}; };

class Drawer
{
  static void write(Shape* shape, DeviceContext& Dc)
  {
    if (Circle* circle = dynamic_cast<Circle*>(shape))
    {
      for (float Angle = 0; Angle < 2*3.14156; Angle += 0.1)
      {
        Dc.FillPixel(cos(Angle) * circle->radius, sin(Angle) * circle-
>radius);
      }
    }
    else if (Square* square = dynamic_cast<Square*>(shape))
    {
      Dc.FillPixel(0, 0);
      Dc.FillPixel(square->edge, 0);
      Dc.FillPixel(square->edge, square->edge);
      Dc.FillPixel(0, square->edge);
    }
  }
};

[toc] | [prev] | [next] | [standalone]


#11534

FromLeigh Johnston <leigh@i42.co.uk>
Date2011-11-16 21:39 +0000
Message-ID<-9udncN-w9UGsFnTnZ2dnUVZ8tqdnZ2d@giganews.com>
In reply to#11532
On 16/11/2011 21:28, Chris Stankevitz wrote:
> On Nov 16, 12:03 pm, red floyd<no.spam.h...@its.invalid>  wrote:
>> You are somewhat correct here.  Have the "write" function return
>> a string which the XML code can display.  By divorcing the I/O from
>> the representation return, you're more general anyways.
>
> Red,
>
> Thank you for your reply.  I believe you have attempted to solve my
> problem by modifying the original shapes to return their "XML
> components" as strings.
>
> Unfortunately this is not what I am interested in because it does not
> scale to what I really want to do.  Instead of writing a long-winded
> response that might not come across correctly, allow me to change my
> original question to use drawing instead of string writing:
>
> ===
>
> Is it possible in C++ to modify "Library B" below to eliminate the
> dynamic_cast and switch statements, while at the same time not doing
> any of the following:
> - Do not use DeviceContext in "Library A"
> - Do not put drawing code in "Library A"
> - Do not put the concept of drawing into "Library A" including adding
> a class Shape::GetPixelsToDraw
>
> My goal is to
> a) not put any reference to drawing into Library A
> b) not use dynamic_cast or switch/if blocks in Library B
>
> The answer might be something like "use factories" or "use template"
> or "this is not possible in c++".
>
> Thank you,
>
> Chris
>
>
> // Library A
> struct Shape { virtual ~Shape() {} };
> struct Circle : public Shape { float radius; };
> struct Square : public Shape { float edge; };
>
> // Library B
>
> #include<cmath>
> struct DeviceContext { void FillPixel(int PixelX, int PixelY) {}; };
>
> class Drawer
> {
>    static void write(Shape* shape, DeviceContext&  Dc)
>    {
>      if (Circle* circle = dynamic_cast<Circle*>(shape))
>      {
>        for (float Angle = 0; Angle<  2*3.14156; Angle += 0.1)
>        {
>          Dc.FillPixel(cos(Angle) * circle->radius, sin(Angle) * circle-
>> radius);
>        }
>      }
>      else if (Square* square = dynamic_cast<Square*>(shape))
>      {
>        Dc.FillPixel(0, 0);
>        Dc.FillPixel(square->edge, 0);
>        Dc.FillPixel(square->edge, square->edge);
>        Dc.FillPixel(0, square->edge);
>      }
>    }
> };

// Library B

struct Drawable
{
   virtual void draw(DeviceContext& Dc) const = 0
};

struct DrawableCircle : Circle, Drawable
{
   virtual void draw(DeviceContext& Dc) { ... }
};

void Drawer::write(Drawable& drawable, DeviceContext& Dc)
{
   drawable.draw(Dc);
}

Perhaps?

/Leigh

[toc] | [prev] | [next] | [standalone]


#11535

FromLeigh Johnston <leigh@i42.co.uk>
Date2011-11-16 21:40 +0000
Message-ID<-9udncJ-w9VQsFnTnZ2dnUVZ8tqdnZ2d@giganews.com>
In reply to#11534
On 16/11/2011 21:39, Leigh Johnston wrote:
> On 16/11/2011 21:28, Chris Stankevitz wrote:
>> On Nov 16, 12:03 pm, red floyd<no.spam.h...@its.invalid> wrote:
>>> You are somewhat correct here. Have the "write" function return
>>> a string which the XML code can display. By divorcing the I/O from
>>> the representation return, you're more general anyways.
>>
>> Red,
>>
>> Thank you for your reply. I believe you have attempted to solve my
>> problem by modifying the original shapes to return their "XML
>> components" as strings.
>>
>> Unfortunately this is not what I am interested in because it does not
>> scale to what I really want to do. Instead of writing a long-winded
>> response that might not come across correctly, allow me to change my
>> original question to use drawing instead of string writing:
>>
>> ===
>>
>> Is it possible in C++ to modify "Library B" below to eliminate the
>> dynamic_cast and switch statements, while at the same time not doing
>> any of the following:
>> - Do not use DeviceContext in "Library A"
>> - Do not put drawing code in "Library A"
>> - Do not put the concept of drawing into "Library A" including adding
>> a class Shape::GetPixelsToDraw
>>
>> My goal is to
>> a) not put any reference to drawing into Library A
>> b) not use dynamic_cast or switch/if blocks in Library B
>>
>> The answer might be something like "use factories" or "use template"
>> or "this is not possible in c++".
>>
>> Thank you,
>>
>> Chris
>>
>>
>> // Library A
>> struct Shape { virtual ~Shape() {} };
>> struct Circle : public Shape { float radius; };
>> struct Square : public Shape { float edge; };
>>
>> // Library B
>>
>> #include<cmath>
>> struct DeviceContext { void FillPixel(int PixelX, int PixelY) {}; };
>>
>> class Drawer
>> {
>> static void write(Shape* shape, DeviceContext& Dc)
>> {
>> if (Circle* circle = dynamic_cast<Circle*>(shape))
>> {
>> for (float Angle = 0; Angle< 2*3.14156; Angle += 0.1)
>> {
>> Dc.FillPixel(cos(Angle) * circle->radius, sin(Angle) * circle-
>>> radius);
>> }
>> }
>> else if (Square* square = dynamic_cast<Square*>(shape))
>> {
>> Dc.FillPixel(0, 0);
>> Dc.FillPixel(square->edge, 0);
>> Dc.FillPixel(square->edge, square->edge);
>> Dc.FillPixel(0, square->edge);
>> }
>> }
>> };
>
> // Library B
>
> struct Drawable
> {
> virtual void draw(DeviceContext& Dc) const = 0
> };
>
> struct DrawableCircle : Circle, Drawable
> {
> virtual void draw(DeviceContext& Dc) { ... }
> };
>
> void Drawer::write(Drawable& drawable, DeviceContext& Dc)
> {
> drawable.draw(Dc);
> }
>
> Perhaps?
>

Oops forgot a "const" there; spot it?

/Leigh

[toc] | [prev] | [next] | [standalone]


#11536

FromLeigh Johnston <leigh@i42.co.uk>
Date2011-11-16 21:43 +0000
Message-ID<-9udnf1-w9UJs1nTnZ2dnUVZ8tqdnZ2d@giganews.com>
In reply to#11535
On 16/11/2011 21:40, Leigh Johnston wrote:
> On 16/11/2011 21:39, Leigh Johnston wrote:
>> On 16/11/2011 21:28, Chris Stankevitz wrote:
>>> On Nov 16, 12:03 pm, red floyd<no.spam.h...@its.invalid> wrote:
>>>> You are somewhat correct here. Have the "write" function return
>>>> a string which the XML code can display. By divorcing the I/O from
>>>> the representation return, you're more general anyways.
>>>
>>> Red,
>>>
>>> Thank you for your reply. I believe you have attempted to solve my
>>> problem by modifying the original shapes to return their "XML
>>> components" as strings.
>>>
>>> Unfortunately this is not what I am interested in because it does not
>>> scale to what I really want to do. Instead of writing a long-winded
>>> response that might not come across correctly, allow me to change my
>>> original question to use drawing instead of string writing:
>>>
>>> ===
>>>
>>> Is it possible in C++ to modify "Library B" below to eliminate the
>>> dynamic_cast and switch statements, while at the same time not doing
>>> any of the following:
>>> - Do not use DeviceContext in "Library A"
>>> - Do not put drawing code in "Library A"
>>> - Do not put the concept of drawing into "Library A" including adding
>>> a class Shape::GetPixelsToDraw
>>>
>>> My goal is to
>>> a) not put any reference to drawing into Library A
>>> b) not use dynamic_cast or switch/if blocks in Library B
>>>
>>> The answer might be something like "use factories" or "use template"
>>> or "this is not possible in c++".
>>>
>>> Thank you,
>>>
>>> Chris
>>>
>>>
>>> // Library A
>>> struct Shape { virtual ~Shape() {} };
>>> struct Circle : public Shape { float radius; };
>>> struct Square : public Shape { float edge; };
>>>
>>> // Library B
>>>
>>> #include<cmath>
>>> struct DeviceContext { void FillPixel(int PixelX, int PixelY) {}; };
>>>
>>> class Drawer
>>> {
>>> static void write(Shape* shape, DeviceContext& Dc)
>>> {
>>> if (Circle* circle = dynamic_cast<Circle*>(shape))
>>> {
>>> for (float Angle = 0; Angle< 2*3.14156; Angle += 0.1)
>>> {
>>> Dc.FillPixel(cos(Angle) * circle->radius, sin(Angle) * circle-
>>>> radius);
>>> }
>>> }
>>> else if (Square* square = dynamic_cast<Square*>(shape))
>>> {
>>> Dc.FillPixel(0, 0);
>>> Dc.FillPixel(square->edge, 0);
>>> Dc.FillPixel(square->edge, square->edge);
>>> Dc.FillPixel(0, square->edge);
>>> }
>>> }
>>> };
>>
>> // Library B
>>
>> struct Drawable
>> {
>> virtual void draw(DeviceContext& Dc) const = 0
>> };
>>
>> struct DrawableCircle : Circle, Drawable
>> {
>> virtual void draw(DeviceContext& Dc) { ... }
>> };
>>
>> void Drawer::write(Drawable& drawable, DeviceContext& Dc)
>> {
>> drawable.draw(Dc);
>> }
>>
>> Perhaps?
>>
>
> Oops forgot a "const" there; spot it?
>
> /Leigh
>

Or if you don't want to derive from library A classes:

struct Drawable
{
virtual void draw(DeviceContext& Dc) const = 0
};

template <typename Shape>
struct DrawableShape : Drawable
{
   Shape& shape;
   DrawableShape(Shape& shape) : shape(shape) {}
   virtual void draw(DeviceContext& Dc) const { /* use shape and Dc here 
*/ }
};

void Drawer::write(Drawable& drawable, DeviceContext& Dc)
{
drawable.draw(Dc);
}

HTH

/Leigh

[toc] | [prev] | [next] | [standalone]


#11537

FromLeigh Johnston <leigh@i42.co.uk>
Date2011-11-16 21:45 +0000
Message-ID<-9udnfx-w9V4s1nTnZ2dnUVZ8tqdnZ2d@giganews.com>
In reply to#11536
On 16/11/2011 21:43, Leigh Johnston wrote:
> On 16/11/2011 21:40, Leigh Johnston wrote:
>> On 16/11/2011 21:39, Leigh Johnston wrote:
>>> On 16/11/2011 21:28, Chris Stankevitz wrote:
>>>> On Nov 16, 12:03 pm, red floyd<no.spam.h...@its.invalid> wrote:
>>>>> You are somewhat correct here. Have the "write" function return
>>>>> a string which the XML code can display. By divorcing the I/O from
>>>>> the representation return, you're more general anyways.
>>>>
>>>> Red,
>>>>
>>>> Thank you for your reply. I believe you have attempted to solve my
>>>> problem by modifying the original shapes to return their "XML
>>>> components" as strings.
>>>>
>>>> Unfortunately this is not what I am interested in because it does not
>>>> scale to what I really want to do. Instead of writing a long-winded
>>>> response that might not come across correctly, allow me to change my
>>>> original question to use drawing instead of string writing:
>>>>
>>>> ===
>>>>
>>>> Is it possible in C++ to modify "Library B" below to eliminate the
>>>> dynamic_cast and switch statements, while at the same time not doing
>>>> any of the following:
>>>> - Do not use DeviceContext in "Library A"
>>>> - Do not put drawing code in "Library A"
>>>> - Do not put the concept of drawing into "Library A" including adding
>>>> a class Shape::GetPixelsToDraw
>>>>
>>>> My goal is to
>>>> a) not put any reference to drawing into Library A
>>>> b) not use dynamic_cast or switch/if blocks in Library B
>>>>
>>>> The answer might be something like "use factories" or "use template"
>>>> or "this is not possible in c++".
>>>>
>>>> Thank you,
>>>>
>>>> Chris
>>>>
>>>>
>>>> // Library A
>>>> struct Shape { virtual ~Shape() {} };
>>>> struct Circle : public Shape { float radius; };
>>>> struct Square : public Shape { float edge; };
>>>>
>>>> // Library B
>>>>
>>>> #include<cmath>
>>>> struct DeviceContext { void FillPixel(int PixelX, int PixelY) {}; };
>>>>
>>>> class Drawer
>>>> {
>>>> static void write(Shape* shape, DeviceContext& Dc)
>>>> {
>>>> if (Circle* circle = dynamic_cast<Circle*>(shape))
>>>> {
>>>> for (float Angle = 0; Angle< 2*3.14156; Angle += 0.1)
>>>> {
>>>> Dc.FillPixel(cos(Angle) * circle->radius, sin(Angle) * circle-
>>>>> radius);
>>>> }
>>>> }
>>>> else if (Square* square = dynamic_cast<Square*>(shape))
>>>> {
>>>> Dc.FillPixel(0, 0);
>>>> Dc.FillPixel(square->edge, 0);
>>>> Dc.FillPixel(square->edge, square->edge);
>>>> Dc.FillPixel(0, square->edge);
>>>> }
>>>> }
>>>> };
>>>
>>> // Library B
>>>
>>> struct Drawable
>>> {
>>> virtual void draw(DeviceContext& Dc) const = 0
>>> };
>>>
>>> struct DrawableCircle : Circle, Drawable
>>> {
>>> virtual void draw(DeviceContext& Dc) { ... }
>>> };
>>>
>>> void Drawer::write(Drawable& drawable, DeviceContext& Dc)
>>> {
>>> drawable.draw(Dc);
>>> }
>>>
>>> Perhaps?
>>>
>>
>> Oops forgot a "const" there; spot it?
>>
>> /Leigh
>>
>
> Or if you don't want to derive from library A classes:
>
> struct Drawable
> {
> virtual void draw(DeviceContext& Dc) const = 0
> };
>
> template <typename Shape>
> struct DrawableShape : Drawable
> {
> Shape& shape;
> DrawableShape(Shape& shape) : shape(shape) {}
> virtual void draw(DeviceContext& Dc) const { /* use shape and Dc here */ }
> };
>
> void Drawer::write(Drawable& drawable, DeviceContext& Dc)
> {
> drawable.draw(Dc);
> }
>

Obviously you would have to specialize draw for different shape types.

HTH.

/Leigh

[toc] | [prev] | [next] | [standalone]


#11538

FromChris Stankevitz <chrisstankevitz@gmail.com>
Date2011-11-16 13:46 -0800
Message-ID<4d5a57fd-c474-4520-8c76-b5c529431e27@i6g2000prm.googlegroups.com>
In reply to#11534
On Nov 16, 1:39 pm, Leigh Johnston <le...@i42.co.uk> wrote:
> struct DrawableCircle : Circle, Drawable

Unfortunately the object that creates my shapes cannot create
DrawableShapes as that library has no dependency on or knowledge of
the concept of drawing.  But thank you for continuing to attempt to
help me.

Chris

[toc] | [prev] | [next] | [standalone]


#11539

FromLeigh Johnston <leigh@i42.co.uk>
Date2011-11-16 21:49 +0000
Message-ID<-9udnf9-w9VFslnTnZ2dnUVZ8tqdnZ2d@giganews.com>
In reply to#11538
On 16/11/2011 21:46, Chris Stankevitz wrote:
> On Nov 16, 1:39 pm, Leigh Johnston<le...@i42.co.uk>  wrote:
>> struct DrawableCircle : Circle, Drawable
>
> Unfortunately the object that creates my shapes cannot create
> DrawableShapes as that library has no dependency on or knowledge of
> the concept of drawing.  But thank you for continuing to attempt to
> help me.

Yeah I wasn't really thinking/trying hard; mostly noise sorry.

/Leigh

[toc] | [prev] | [next] | [standalone]


#11531

FromLeigh Johnston <leigh@i42.co.uk>
Date2011-11-16 20:35 +0000
Message-ID<y-idnYLWxbYbg1nTnZ2dnUVZ8hqdnZ2d@giganews.com>
In reply to#11528
On 16/11/2011 19:14, Chris Stankevitz wrote:
> On Nov 16, 10:52 am, Ian Collins<ian-n...@hotmail.com>  wrote:
>> Something like:
>>
>> struct Shape {
>>     virtual void write() = 0;};
>
> Ian,
>
> I prefer/require a solution in which the shapes themselves are not
> writing out XML -- I want the XML related code restricted to the
> "XmlWriter" class in "Library B".  This appears to be an overly
> draconian requirement in this simple example, but should make more
> sense if you consider adding something like a "drawing" or "network"
> class that would introduce dependencies on drawing or socket code.
>
> I want drawing/xml/socket code relegated to "Library B" without
> compile or link dependencies in "Library A".

Something like the following perhaps?

#include <iostream>
#include <string>
#include <vector>
#include <memory>

struct serializer
{
	virtual void write(const std::string& shapeName, const std::string& 
dimensionName, float dimensionValue) const = 0;
};

struct shape
{
	virtual void write(const serializer& writer) const = 0;
};

struct circle : shape
{
	circle(float radius) : radius(radius) {}
	virtual void write(const serializer& writer) const
	{
		writer.write("Circle", "Radius", radius);
	}
	float radius;
};

struct square : shape
{
	square(float edge) : edge(edge) {}
	virtual void write(const serializer& writer) const
	{
		writer.write("Square", "Edge", edge);
	}
	float edge;
};

struct xml_writer : serializer
{
	virtual void write(const std::string& shapeName, const std::string& 
dimensionName, float dimensionValue) const
	{
		std::cout << "<" << shapeName << " " << dimensionName << "=\"" << 
dimensionValue << "\" />\n";
	}
};

int main()
{
	typedef std::tr1::shared_ptr<shape> shape_ptr;
	typedef std::vector<shape_ptr> shapes_t;
	shapes_t shapes;
	shapes.push_back(shape_ptr(new circle(7.0f)));
	shapes.push_back(shape_ptr(new square(42.0f)));
	xml_writer w;
	for (shapes_t::const_iterator i = shapes.begin(); i != shapes.end(); ++i)
		(**i).write(w);
}

[toc] | [prev] | [next] | [standalone]


#11544

FromChris Stankevitz <chrisstankevitz@gmail.com>
Date2011-11-16 13:38 -0800
Message-ID<f1560d93-85cc-4481-8d40-21471c8bd85a@u37g2000prh.googlegroups.com>
In reply to#11531
On Nov 16, 12:35 pm, Leigh Johnston <le...@i42.co.uk> wrote:
>         virtual void write(const serializer& writer) const


Leigh,

Thank you for your reply.  I believe you have effectively modified the
base class to return the XML components as strings.  This is not what
I am attempting to do as it requires me to modify the base class to
assume it will be serialized. I'm looking for an approach in which the
base class is not modified or at least is modified only in a way that
allows a Factory or Template or some other technique to give shape
details to another library.  I do not want to modify the base class to
share "serializing" details.  I try to explain this a little better in
my reply to Red.

Thank you,

Chris

[toc] | [prev] | [next] | [standalone]


#11533

FromIan Collins <ian-news@hotmail.com>
Date2011-11-17 10:37 +1300
Message-ID<9iioo8Fi5oU16@mid.individual.net>
In reply to#11528
On 11/17/11 08:14 AM, Chris Stankevitz wrote:
> On Nov 16, 10:52 am, Ian Collins<ian-n...@hotmail.com>  wrote:
>> Something like:
>>
>> struct Shape {
>>     virtual void write() = 0;};
>
> Ian,
>
> I prefer/require a solution in which the shapes themselves are not
> writing out XML -- I want the XML related code restricted to the
> "XmlWriter" class in "Library B".  This appears to be an overly
> draconian requirement in this simple example, but should make more
> sense if you consider adding something like a "drawing" or "network"
> class that would introduce dependencies on drawing or socket code.
>
> I want drawing/xml/socket code relegated to "Library B" without
> compile or link dependencies in "Library A".

Well you have to look seriously at whether a shape knows how to write 
its self, or an XmlWriter knows how to write a shape.  If it's the 
latter, you gave to provide a means for an XmlWriter to access the 
required information.  This can lead to significant complexity and 
coupling in your design.

It gets more complex still if you consider drawing a shape.

-- 
Ian Collins

[toc] | [prev] | [next] | [standalone]


#11540

FromChris Stankevitz <chrisstankevitz@gmail.com>
Date2011-11-16 13:41 -0800
Message-ID<fb2a37ad-a131-4aa6-a4eb-1b85d0993f8e@j19g2000pro.googlegroups.com>
In reply to#11533
On Nov 16, 1:37 pm, Ian Collins <ian-n...@hotmail.com> wrote:
> Well you have to look seriously at whether a shape knows how to write
> its self, or an XmlWriter knows how to write a shape.  If it's the
> latter, you have to provide a means for an XmlWriter to access the
> required information.

Yes, it is the latter that I would like to do.

> This can lead to significant complexity

Yes, I am looking for complexity and am curious if it is possible to
do this with c++.

> It gets more complex still if you consider drawing a shape.

Yes, I am trying to draw Shapes without Shapes knowing how to draw
themselves.  Is it possible to do this in c++ without using
dynamic_cast or lots of switch/if statements?

Thank you,

Chris

[toc] | [prev] | [next] | [standalone]


#11541

FromIan Collins <ian-news@hotmail.com>
Date2011-11-17 10:56 +1300
Message-ID<9iipskFi5oU17@mid.individual.net>
In reply to#11540
On 11/17/11 10:41 AM, Chris Stankevitz wrote:
> On Nov 16, 1:37 pm, Ian Collins<ian-n...@hotmail.com>  wrote:
>> Well you have to look seriously at whether a shape knows how to write
>> its self, or an XmlWriter knows how to write a shape.  If it's the
>> latter, you have to provide a means for an XmlWriter to access the
>> required information.
>
> Yes, it is the latter that I would like to do.
>
>>   This can lead to significant complexity
>
> Yes, I am looking for complexity and am curious if it is possible to
> do this with c++.
>
>> It gets more complex still if you consider drawing a shape.
>
> Yes, I am trying to draw Shapes without Shapes knowing how to draw
> themselves.  Is it possible to do this in c++ without using
> dynamic_cast or lots of switch/if statements?

The problem has little to do with C++.  The issue of who knows how to do 
what is common to any language.

The literal answer to your question is yes.  You can always replace 
conditionals with virtual member functions.

-- 
Ian Collins

[toc] | [prev] | [next] | [standalone]


#11542

FromChris Stankevitz <chrisstankevitz@gmail.com>
Date2011-11-16 14:03 -0800
Message-ID<0a80b56f-6702-494f-8ba4-ddefdf7fcaf2@q39g2000prg.googlegroups.com>
In reply to#11541
On Nov 16, 1:56 pm, Ian Collins <ian-n...@hotmail.com> wrote:
> You can always replace conditionals with virtual member functions.

I assume in the drawing case you are suggesting I add a virtual
function "GetVerticies" or a virtual function "Draw".  This is now
what I want for these reasons:

1. I have to modify the Shape class to be aware that it is being drawn
2. Some shapes cannot be drawn with "verticies" and need to be drawn
carefully and uniquely -- for example a doughnut that has a hole in
the middle.

Thank you,

Chris

[toc] | [prev] | [next] | [standalone]


#11543

FromIan Collins <ian-news@hotmail.com>
Date2011-11-17 11:12 +1300
Message-ID<9iiqq0Fi5oU18@mid.individual.net>
In reply to#11542
On 11/17/11 11:03 AM, Chris Stankevitz wrote:
> On Nov 16, 1:56 pm, Ian Collins<ian-n...@hotmail.com>  wrote:
>> You can always replace conditionals with virtual member functions.
>
> I assume in the drawing case you are suggesting I add a virtual
> function "GetVerticies" or a virtual function "Draw".  This is now
> what I want for these reasons:
>
> 1. I have to modify the Shape class to be aware that it is being drawn
> 2. Some shapes cannot be drawn with "verticies" and need to be drawn
> carefully and uniquely -- for example a doughnut that has a hole in
> the middle.

So how would a generic drawing class be expected to know this?  It would 
have to changed for each new shape.

Does your window manager know how to render every type of window on your 
system?

-- 
Ian Collins

[toc] | [prev] | [next] | [standalone]


#11548

FromChris Stankevitz <chrisstankevitz@gmail.com>
Date2011-11-16 15:20 -0800
Message-ID<f2e85751-b240-4f9c-81a3-7b3fff09bd80@f3g2000pri.googlegroups.com>
In reply to#11543
On Nov 16, 2:12 pm, Ian Collins <ian-n...@hotmail.com> wrote:
> So how would a generic drawing class be expected to know this?

This is basically the question I am asking this group.

Below is a pseudocode answer to the question that
 - leaves Shape, Circle, and Square untouched (good)
 - places no drawing dependency on the shapes (good)
 - leaves drawing code entirely in the Drawer classes (good)
 - does not have switch or if statements (good)
 * does use a dynamic cast (BAD)

Can you (or anyone else) come up with some c++ pseudocode that
 - leaves Shape, Circle, and Square untouched (good)
 - places no drawing dependency on the shapes (good)
 - leaves drawing code entirely in the Drawer classes (good)
 - does not have switch or if statements (good)
 - does not use a dynamic cast (good)

Chris

=====

//----------
struct Drawer
{
  virtual void Draw(Shape* shape) = 0;
};

//----------
struct CircleDrawer : public Drawer
{
  void Draw(Shape* shape)
  {
    // dynamic_cast<Circle*>(shape)
    // draw the circle
  }
};

//----------
struct SquareDrawer : public Drawer
{
  void Draw(Shape* shape)
  {
    // dynamic_cast<Square*>(shape)
    // draw the square
  }
};

//----------
struct DrawerCreator
{
  virtual Drawer* GetNewDrawer() = 0;
  virtual bool CanDraw(Shape* shape) = 0;
};

//----------
struct CircleDrawerCreator : public DrawerCreator
{
  Drawer* GetNewDrawer() { return new CircleDrawer; }
  bool CanDraw(Shape* shape) { return dynamic_cast<Circle*>(shape); }
};

//----------
struct SqareDrawerCreator : public DrawerCreator
{
  Drawer* GetNewDrawer() { return new SquareDrawer; }
  bool CanDraw(Shape* shape) { return dynamic_cast<Square*>(shape); }
};

//----------
struct DrawerManager
{
  void RegisterDrawerCreator(DrawerCreator* dc)
  {
    drawers.push_back(dc);
  }

  void Draw(Shape* shape)
  {
    if (Drawer* drawer = GetDrawer(shape))
    {
      drawer->Draw(shape);
    }
  }

  Drawer* GetDrawer(Shape* shape)
  {
    for (int i = 0; i < drawers.size(); ++i)
    {
      if (drawers[i]->CanDraw(shape))
      {
        return drawers[i]->GetNewDrawer();
      }
    }

    return 0;
  }

  vector<Drawer*> drawers;
};

//----------
int main()
{
  DrawerManager drawer_manager;

  drawer_manager.RegisterDrawerCreator(new CircleDrawerCreator);
  drawer_manager.RegisterDrawerCreator(new SquareDrawerCreator);

  Shape* shape1 = new Circle;
  Shape* shape2 = new Square;

  drawer_manager.Draw(shape1);
  drawer_manager.Draw(shape2);
}

[toc] | [prev] | [next] | [standalone]


#11552

FromWerner <werasm@gmail.com>
Date2011-11-16 23:39 -0800
Message-ID<94cb8684-e1aa-47bf-b843-09a2894b6683@r9g2000vbw.googlegroups.com>
In reply to#11548
On Nov 17, 1:20 am, Chris Stankevitz <chrisstankev...@gmail.com>
wrote:

> Below is a pseudocode answer to the question that
>  - leaves Shape, Circle, and Square untouched (good)
>  - places no drawing dependency on the shapes (good)
>  - leaves drawing code entirely in the Drawer classes (good)
>  - does not have switch or if statements (good)
>  * does use a dynamic cast (BAD)
>
> Can you (or anyone else) come up with some c++ pseudocode that
>  - does not use a dynamic cast (good)

I can't see why using dynamic cast is so bad. It is not as
if you have an if/else style of programming that requires
constant modification. dynamic_cast under your control that
requires no modification is good (except for being a tid
slower, perhaps).

You might want to remove the burden from your client though (see
below):

#include <vector>

struct Shape{};
struct Circle : Shape{};
struct Square : Shape{};

struct AbstractDrawer
{
  virtual void Draw(Shape* shape) = 0;

};

template <class ShapeT>
struct TypedDrawer : AbstractDrawer
{
    typedef ShapeT shape_type;

  protected:
    virtual void DoDraw( shape_type& shape ) = 0;
      //{ Default implementation ??? }

  private:
    virtual void Draw( Shape* shape )
    {
      DoDraw( dynamic_cast<shape_type&>(*shape) );
    }
};

struct CircleDrawer : TypedDrawer<Circle>
{
  protected:
    virtual void DoDraw( Circle& shape )
    {
      //Implementation
    }
};

struct SquareDrawer : TypedDrawer<Square>
{
  protected:
    virtual void DoDraw( Square& shape )
    {
      //Implementation
    }
};

//----------
struct AbstractDrawerCreator
{
  virtual AbstractDrawer* GetNewDrawer() = 0;
  virtual bool CanDraw(Shape* shape) = 0;
};

template <class DrawerT>
struct TypedDrawerCreator : AbstractDrawerCreator
{
  private:
    typedef DrawerT drawer_type;
    typedef typename DrawerT::shape_type shape_type;

    virtual drawer_type* GetNewDrawer() const
    {
      return new drawer_type;
    }
    virtual bool CanDraw( Shape* shape ) const
    {
      return dynamic_cast<shape_type*>(shape);
    }
};

typedef TypedDrawerCreator<CircleDrawer> CircleDrawerCreator;
typedef TypedDrawerCreator<SquareDrawer> SquareDrawerCreator;
//etc...


//[Werner Erasmus: Left this in as I've removed compiler
//  errors]
struct DrawerManager
{
  void RegisterDrawerCreator(AbstractDrawerCreator* dc)
  {
    drawers.push_back(dc);
  }

  void Draw(Shape* shape)
  {
    if (AbstractDrawer* drawer = GetDrawer(shape))
    {
      drawer->Draw(shape);
    }
  }

  AbstractDrawer* GetDrawer(Shape* shape)
  {
    for (int i = 0; i < drawers.size(); ++i)
    {
      if (drawers[i]->CanDraw(shape))
      {
        return drawers[i]->GetNewDrawer();
      }
    }

    return 0;
  }

  std::vector<AbstractDrawerCreator*> drawers;
};


[toc] | [prev] | [next] | [standalone]


Page 1 of 3  [1] 2 3  Next page →

Back to top | Article view | comp.lang.c++


csiph-web