const problems with one class referencing another

Discussion in 'C++' started by Torsten Wiebesiek, Aug 10, 2007.

  1. Hi folks,

    currently I'm writing image classes for easier handling of Intel's IPP library.

    My idea is to have to different classes. One class that represents a complete
    image and deals with all the memeory management stuff, and another class, that
    is only a tile of the image. Let's call the first MemoryImage, and the second
    ReferenceImage.

    My code works well for creating non const and const reference images to a non
    const memory image. Unfortunately, it doesn't work for const memory images.

    The following code illustrates my problem. It's neither stylistically nor
    functionally perfect (in fact it's neglecting the identical byte offsets
    between consecutive images lines, even though the image widths might be
    different.


    class MemImage {

    public:

    // Create image.
    MemImage(int width, int height) : m_data(0) {

    // check dimensions and allocate aligned memory
    }

    // Get width of image.
    int getWidth() const { return m_width; }

    // Get height of image.
    int getHeight() const { return m_height; }

    // Get pointer to image data.
    unsigned char* getData() { return m_data; }

    // Get const pointer to image data.
    const unsigned char* getData() const { return m_data; }

    protected:

    unsigned char * m_data;
    int m_width;
    int m_height;

    }; // class MemImage


    class RefImage {

    public:

    RefImage(MemImage &image, int x, int y, int width, int height)
    : m_data(image.getData()+y*image.getWidth()+x), m_width(width), m_height(height)
    {}

    // Get pointer to image data.
    unsigned char* getData() { return m_data; }

    // Get const pointer to image data.
    const unsigned char* getData() const { return m_data; }

    protected:

    unsigned char *m_data;
    int m_width;
    int m_height;

    }; // class RefImage


    With the example code above, its possible to do:

    void f()
    {
    MemImage m(400,300);
    RefImage r(m, 40, 30, 200, 150);
    const RefImge c(m, 40, 30, 200, 150);
    }

    It's also possible to change image data of m through r.getData()

    The code breaks with:
    void g()
    {
    const MemImage m(400,300);
    const RefImge c(m, 40, 30, 200, 150);
    }

    Changing the constructor of RefImage to

    RefImage(const MemImage &image, int x, int y, int width, int height)
    : m_data(image.getData()+y*image.getWidth()+x), m_width(width), m_height(height)
    {}

    fails due to the initialization of unsigned char m_data with a const unsigned char.

    Changing the member m_data of RefImage to const unsigned char, the constructor works,
    but it's no longer possible to have write access to non const MemImages via a RefImage.

    Can anyone break this vicious circle?

    Thanks in advance,

    Torsten
    Torsten Wiebesiek, Aug 10, 2007
    #1
    1. Advertising

  2. Torsten Wiebesiek

    Jim Langston Guest

    "Torsten Wiebesiek" <-hannover.de> wrote in message
    news:f9h9io$pl9$...
    > Hi folks,
    >
    > currently I'm writing image classes for easier handling of Intel's IPP
    > library.
    >
    > My idea is to have to different classes. One class that represents a
    > complete
    > image and deals with all the memeory management stuff, and another class,
    > that
    > is only a tile of the image. Let's call the first MemoryImage, and the
    > second
    > ReferenceImage.
    >
    > My code works well for creating non const and const reference images to a
    > non
    > const memory image. Unfortunately, it doesn't work for const memory
    > images.
    >
    > The following code illustrates my problem. It's neither stylistically nor
    > functionally perfect (in fact it's neglecting the identical byte offsets
    > between consecutive images lines, even though the image widths might be
    > different.
    >
    >
    > class MemImage {
    >
    > public:
    >
    > // Create image.
    > MemImage(int width, int height) : m_data(0) {
    >
    > // check dimensions and allocate aligned memory
    > }
    >
    > // Get width of image.
    > int getWidth() const { return m_width; }
    >
    > // Get height of image.
    > int getHeight() const { return m_height; }
    >
    > // Get pointer to image data.
    > unsigned char* getData() { return m_data; }
    >
    > // Get const pointer to image data.
    > const unsigned char* getData() const { return m_data; }
    >
    > protected:
    >
    > unsigned char * m_data;
    > int m_width;
    > int m_height;
    >
    > }; // class MemImage
    >
    >
    > class RefImage {
    >
    > public:
    >
    > RefImage(MemImage &image, int x, int y, int width, int height)
    > : m_data(image.getData()+y*image.getWidth()+x), m_width(width),
    > m_height(height)
    > {}
    >
    > // Get pointer to image data.
    > unsigned char* getData() { return m_data; }
    >
    > // Get const pointer to image data.
    > const unsigned char* getData() const { return m_data; }
    >
    > protected:
    >
    > unsigned char *m_data;
    > int m_width;
    > int m_height;
    >
    > }; // class RefImage
    >
    >
    > With the example code above, its possible to do:
    >
    > void f()
    > {
    > MemImage m(400,300);
    > RefImage r(m, 40, 30, 200, 150);
    > const RefImge c(m, 40, 30, 200, 150);
    > }
    >
    > It's also possible to change image data of m through r.getData()
    >
    > The code breaks with:
    > void g()
    > {
    > const MemImage m(400,300);
    > const RefImge c(m, 40, 30, 200, 150);


    I can get this to work with an extremly ugly constant cast.

    const RefImage c(*(const_cast<MemImage*>( &m )), 40, 30, 200, 150);

    I've been trying various things and can't figure it out. It seems that
    because RefImage has an
    unsigned char* and is trying to initialize it from a const unsigned char*
    from unsigned char*.

    The only thing I've found so far that works is making m_data public, and
    initalizing with

    RefImage(const MemImage &image, int x, int y, int width, int height)
    : m_data(image.m_data+y*image.getWidth()+x), m_width(width),
    m_height(height)
    {}


    > }
    >
    > Changing the constructor of RefImage to
    >
    > RefImage(const MemImage &image, int x, int y, int width, int height)
    > : m_data(image.getData()+y*image.getWidth()+x), m_width(width),
    > m_height(height)
    > {}
    >
    > fails due to the initialization of unsigned char m_data with a const
    > unsigned char.
    >
    > Changing the member m_data of RefImage to const unsigned char, the
    > constructor works,
    > but it's no longer possible to have write access to non const MemImages
    > via a RefImage.
    >
    > Can anyone break this vicious circle?
    >
    > Thanks in advance,
    >
    > Torsten
    >
    Jim Langston, Aug 10, 2007
    #2
    1. Advertising

  3. Hi!

    Torsten Wiebesiek schrieb:
    > Can anyone break this vicious circle?


    No. You have to create a ConstRefImage class. But you can inherit it.

    struct ConstRefImage {
    ConstRefImage(MemoryImage const& m, ...)
    : constImage(m)
    { ... }
    MemoryImage const& constImage;
    ... //some const member functions
    };
    struct RefImage : ConstRefImage {
    RefImage(MemoryImage& m, ...)
    : ConstRefImage(m) //cast to const
    , image(m)
    { ... }
    MemoryImage & image;
    ... //some non-const member functions
    };

    void foo(ConstRefImage const& image) { ... }
    void bar()
    {
    MemoryImage m(...);
    RefImage r(m, ...);
    foo(r); //works
    };

    HTH

    Some other advise: you can use std::vector instead of raw memory to
    avoid memory management issues. The std::vector is required to allocate
    continuous memory. So "&v[0]" will give you the pointer you need.
    Getting raw memory management correct is not trivial and should be avoided.

    Frank
    Frank Birbacher, Aug 10, 2007
    #3
  4. >> Can anyone break this vicious circle?
    >
    > No. You have to create a ConstRefImage class. But you can inherit it.
    >
    > struct ConstRefImage {
    > ConstRefImage(MemoryImage const& m, ...)
    > : constImage(m)
    > { ... }
    > MemoryImage const& constImage;
    > ... //some const member functions
    > };
    > struct RefImage : ConstRefImage {
    > RefImage(MemoryImage& m, ...)
    > : ConstRefImage(m) //cast to const
    > , image(m)
    > { ... }
    > MemoryImage & image;
    > ... //some non-const member functions
    > };
    >
    > void foo(ConstRefImage const& image) { ... }
    > void bar()
    > {
    > MemoryImage m(...);
    > RefImage r(m, ...);
    > foo(r); //works
    > };


    Frank, that was a very good hint. Thanks! :)

    I now have the following class hierarchy:

    class ConstImage {...};
    class Image : public virtual ConstImage {...};

    class MemImage : public Image {...};

    class ConstRefImage : public virtual ConstImage {...};
    class RefImage : public ConstRefImage, public Image {...};

    Virtual inheritance, because ConstImage is not abstract but
    deals with height and width information. Seems to work.


    > Some other advise: you can use std::vector instead of raw memory to
    > avoid memory management issues. The std::vector is required to allocate
    > continuous memory. So "&v[0]" will give you the pointer you need.
    > Getting raw memory management correct is not trivial and should be avoided.


    I'd love to, but I'm not sure, whether it's really allocating properly
    alligned memory. Therefore, I use Intels IPP Memory allocation function:

    Ipp<datatype>* ippiMalloc_<mod>(int width, int height, int* pStepBytes);

    It's neither very nice nor very convenient, but, well, it's a speed optimized
    C library. There are some design drawback, but at least it's very fast.


    Regards,

    Torsten
    Torsten Wiebesiek, Aug 13, 2007
    #4
    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. Replies:
    11
    Views:
    1,090
  2. Javier
    Replies:
    2
    Views:
    549
    James Kanze
    Sep 4, 2007
  3. 0m
    Replies:
    26
    Views:
    1,095
    Tim Rentsch
    Nov 10, 2008
  4. fungus
    Replies:
    13
    Views:
    874
    fungus
    Oct 31, 2008
  5. Replies:
    2
    Views:
    531
    Andrew Koenig
    Feb 9, 2009
Loading...

Share This Page