Solved

Simple question on pointers and classes that hold pointers

Posted on 2004-04-17
21
402 Views
Last Modified: 2008-02-01
Hi,

I'm just confusing myself here, but I have a class CImageResource which I basically want to be a representation of a bitmap (I'm using gdi+) with a few extra methods and variables.

I have a dynamic array of these classes, so that's a pointer to the first element right?

Now, my question is... how do I want this to look? If we just talk about the class 'holding' a bitmap, should it be a Bitmap, pointer to bitmap, or what? Because basically, I need the array initialised, then a class loads a bitmap from a file, and sets an element in the array's bitmap to that one. The class that sets this bitmap, later needs to access it again to draw it. With a dynamic array like this (I've got CImageResource *pics = new CImageResource[numberOfElements]; and nothing in the CImageResource constructor) do I need to separately initialise each element to something, or for that matter the bitmaps in each element?

I can get it to compile, but I get access violation errors on debugging,

Thanks
0
Comment
Question by:shifty_mc
  • 11
  • 9
21 Comments
 

Author Comment

by:shifty_mc
ID: 10849620
Just to make it clearer, at the mo I've got

void SetPic(Gdiplus::Bitmap *pic);
Gdiplus::Bitmap *img;
in my CImageResource header, and
void CImageResource::SetPic(Bitmap *pic)
{
      this->img = pic;
}
in the cpp file.

I've then got
bmp = Gdiplus::Bitmap::FromFile( filename,true );
pics[0].SetPic(bmp);

and the debugger gives me an access violation error on the line this->img = pic;

I just figured I was doing something wrong with the pointers because I'm not really sure what I'm doing.
0
 
LVL 19

Expert Comment

by:mrwad99
ID: 10849734
>> I have a dynamic array of these classes, so that's a pointer to the first element right?

Yes.

>> should it be a Bitmap, pointer to bitmap, or what?

If you create the array on the heap (which you do by stating 'new') then you need to add Bitmaps.  If you were adding pointers to bitmaps, you would have declared the array as

CImageResource** pics = new CImageResource* [numberOfElements]; // Created on the heap

or simply

CImageResource* pics[10]; // Created on the stack

>> do I need to separately initialise each element to something, or for that matter the bitmaps in each element

As long as you have a default constructor, no.  If you did not, this would not compile.

This may be useful for you: http://pweb.netcom.com/~tjensen/ptr/pointers.htm
0
 

Author Comment

by:shifty_mc
ID: 10849827
ok, so where before I had each CImageResource holding a pointer to a bitmap, now I've changed it to an actual bitmap,
but it won't compile - telling me...
'Bitmap' : no appropriate default constructor available
and pointing to the line in CImageResource default constructor - what does this mean?

Also, when I load a bitmap from a file in my other class - it returns a pointer to a bitmap, so when I pass this pointer to the SetPic method of CImageResource, how should this look? It compiles with
void CImageResource::SetPic(Bitmap *pic)
{
      this->img = *pic;
}
This right? (still gives me the compile error I said above tho)

Thanks (sorry - I know this is very simple stuff - I'm just confusing myself more the more time I spend on it)
0
The Eight Noble Truths of Backup and Recovery

How can IT departments tackle the challenges of a Big Data world? This white paper provides a roadmap to success and helps companies ensure that all their data is safe and secure, no matter if it resides on-premise with physical or virtual machines or in the cloud.

 
LVL 19

Expert Comment

by:mrwad99
ID: 10849963
>> before I had each CImageResource holding a pointer to a bitmap

Ah, now you make it clear that CImageResource is not the same as Bitmap; I thought the former was just another name you had given the bitmap.

It was perfectly acceptable to do what you were doing before.  The compiler is now complaining since when you try to construct a CImageResource, all the members of this class must be constructed first.  These members include your bitmap, (I presume it is declared something like Bitmap m_bitmap) and since there is no default constructor for a bitmap object, m_bitmap cannot be constructed.  

So, change it back to a Bitmap*, and it will compile.  Of course however, when you construct a CImageResource object now, this Bitmap* will not point to anything as yet, so in the constructor for CImageResource you should state m_bitmap = NULL or if you use an initialisation list, m_bitmap(NULL).

Now, your access violation is probably coming from the fact that when you created a CImageResource object, you never assigned the bitmap member to a valid bitmap object.

So, with your original code

CImageResource *pics = new CImageResource[numberOfElements];

and

bmp = Gdiplus::Bitmap::FromFile( filename,true );
pics[0].SetPic(bmp);

it is evident that pics[0] does not have a valid bitmap pointer.

Run to the line

this->img = pic;

and have a look at the value of this->img; I bet it is undefined.


>>sorry - I know this is very simple stuff - I'm just confusing myself more the more time I spend on it

The very first question I asked on EE was about arrays of pointers; I know it is difficult and there is no need to appologise !

HTH
0
 

Author Comment

by:shifty_mc
ID: 10849999
Ah ok, sorry about that,

So when I run the debugger, it gives the value of this->img as
CXX0030: Error: expression cannot be evaluated

Does that means it's undefined?

What then? Because I know I'm not doing anything wrong with the loading of the bitmap - I did it before I tried to abstract it in this way and it worked fine...
0
 

Author Comment

by:shifty_mc
ID: 10850008
sorry - should have said - I did add the code
this->img = NULL;
in the CImageResource constructor
0
 
LVL 9

Expert Comment

by:Cayce
ID: 10850017
Don't use arrays for holding objects, you should use a container.

The easies:

#include <vector>
using namescape std;
...
     vector<CImageResource*> Images;

     vector.resize(NUMBER_OF_IMAGES);

    for(int i = 0; i < NUMBER_OF_IMAGES; i++)
     vector[i] = new CImageResource(...);

// work with the images, increase the size of vector if needed to hold more images

      for(int i = 0; i < NUMBER_OF_IMAGES; i++)
        delete vector[i];

0
 
LVL 19

Expert Comment

by:mrwad99
ID: 10850033
Yes that means it is undefined.  You need to state

m_bitmap = &(some bitmap object)

or

m_bitmap = (pointer to a bitmap object)

>> Also, when I load a bitmap from a file in my other class - it returns a pointer to a bitmap

so you just need to assign m_bitmap to this pointer you get returned.
0
 

Author Comment

by:shifty_mc
ID: 10850056
but that's it exactly what I'm doing - assigning m_bitmap (or in my case img) to the pointer returned (I think)...

pics[0].SetPic(bmp);
where bmp is the pointer returned.

and
void CImageResource::SetPic(Bitmap *pic)
{
      this->img = pic;
}
0
 
LVL 19

Expert Comment

by:mrwad99
ID: 10850069
So are you sure that the pointer returned is not NULL ?

Add ASSERT(bmp name returned)

or breakpoint on the line after you get the returned pointer.  See it it can be evaluated or not.
0
 

Author Comment

by:shifty_mc
ID: 10850089
positive, because if I try and do everything without using the array of CImageResources (ie just displaying the image - using
DrawImage( bmp, Rect(rect.left,rect.top,w,h), 0, 0, w, h, UnitPixel, &ia);
where bmp is the same thing,
it works fine - just tried it again.
0
 
LVL 19

Expert Comment

by:mrwad99
ID: 10850128
Hmmmm, so the problem remains that this->img is invalid.  You must be doing something else wrong somewhere; can you post all your code in the form of a downloadable zip file ??
0
 

Author Comment

by:shifty_mc
ID: 10850147
absolutely - I'd appreciate the effort and certainly increase the points.
How do I go about doing that - do I need to have somewhere you can download it from or can I post it here somehow?
0
 
LVL 19

Expert Comment

by:mrwad99
ID: 10850157
Well that would be the easiest thing if you had some online webspace, eg with geocities.  Then zip your project (excluding debug and release dir) and upload it.  Then post the link.
0
 

Author Comment

by:shifty_mc
ID: 10850215
haha, unfortunately not - I did try to get my ntl webspace working quite recently actually but something was going wrong on their end and I never bothered following it up.
I can post my email (I have a kind of temporary one that I'm not too worried about), which you in turn could send your emai address to if you liked, but don't worry if not - I know it's not ideal. Most of the project must be irrelevant anyway, but I could post the full code for the three classes involved (a base class CPlugin which holds an array of CImageResources, then a derived class CSliderShow that uses the array).

But having said that - just looking at it - they're not huge but with the header files I think a bit much (220 lines ish)
0
 
LVL 19

Expert Comment

by:mrwad99
ID: 10850229
Yeah, post relevant code here then.  It is against EE policy to give on participant in a question unfair advantage over another; this way anyone reading the question can help you.
0
 

Author Comment

by:shifty_mc
ID: 10850277
ok, well I'll post the main stuff without VC6's extras, or the includes etc...
First off the CImageResource header...
////////////////////////////////////////////////////////////////////////
class CImageResource  
{
public:
      CImageResource();
      virtual ~CImageResource();      
      void SetPic(Gdiplus::Bitmap *pic);
      Gdiplus::Bitmap *img;
};
////////////////////////////////////////////////////////////////////////

and ImageResource.cpp...
/////////////////////////////////////////////////////////////////////////
CImageResource::CImageResource()
{
      this->img = NULL;
}

CImageResource::~CImageResource()
{

}

void CImageResource::SetPic(Bitmap *pic)
{
      this->img = pic;
}
////////////////////////////////////////////////////////////////////////

Then the base class CPlugin header...
//////////////////////////////////////////////////////////////////////////
class CPlugin  
{
public:
      CPlugin();
      CPlugin(int n);
      virtual ~CPlugin();
      ColorMatrix GetAlphaBlendColourMatrix(float nAlpha);
      CImageResource *pics;
};
//////////////////////////////////////////////////////////////////////////////

And the Plugin.cpp file...
//////////////////////////////////////////////////////////////////////
CPlugin::CPlugin()
{
      TRACE("Default plugin constructor\n");
}

CPlugin::CPlugin(int numberOfElements)
{
      TRACE("In plugin constructor\nInitialising array of pics with %d element(s)\n", numberOfElements);
      CImageResource *pics = new CImageResource[numberOfElements];
}

CPlugin::~CPlugin()
{
      delete[] pics;
}

ColorMatrix CPlugin::GetAlphaBlendColourMatrix(float nAlpha)
{
      // validate parameters:
      if (nAlpha < 0 || nAlpha > 1)
            //do exception
      using namespace Gdiplus;
      // generate a colour matrix;
      ColorMatrix clrMatrix = {
                              1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
                              0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
                              0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
                              0.0f, 0.0f, 0.0f, nAlpha, 0.0f,
                              0.0f, 0.0f, 0.0f, 0.0f, 1.0f };
      return clrMatrix;
}
//////////////////////////////////////////////////////////////////////////////////////

Finally, the derived CSlideShow header...
///////////////////////////////////////////////////////////////////////////////////
class CSlideshow : public CPlugin
{
public:
      
      CSlideshow();
      virtual ~CSlideshow();
      void LoadPics();
      void Paint(Graphics &g);
      void Timer(int nSpan);

      float ImageOpacity;      
      int UpdatePeriod;
      int current_picture;      
      Bitmap *bmp;

};
/////////////////////////////////////////////////////////////////////////////

And SlideShow.cpp...
//////////////////////////////////////////////////////////////////////

CSlideshow::CSlideshow():CPlugin(1)
{
      TRACE("In Slideshow constructor\n");
      UpdatePeriod = 3;
      current_picture = -1;
}

CSlideshow::~CSlideshow()
{

}

void CSlideshow::Timer(int nSpan)
{
      if (nSpan <= 1 )
      {
            TRACE("Fading in\n");
            ImageOpacity += 0.1f;
            // fade in
      }
      if (nSpan >= UpdatePeriod)
      {
            // Load new pic/pics
            CSaverWnd::m_timeStart = CTime::GetCurrentTime();
            LoadPics();
      }
      if (nSpan >= (UpdatePeriod-1))
      {
            TRACE("Fading out\n");
            ImageOpacity -= 0.1f;
            //ia = GetAlphaBlendColourMatrix(ImageOpacity);
            // fade out
      }
      if (ImageOpacity > 1.0f) ImageOpacity = 1.0f;
      if (ImageOpacity < 0.0f) ImageOpacity = 0.0f;
}

void CSlideshow::Paint(Graphics &g)
{
      if(current_picture!= -1)
      {
            ImageAttributes ia;
            //TRACE("ImageOpactiy set to %f\n", ImageOpacity);
            ia.SetColorMatrix(&GetAlphaBlendColourMatrix(ImageOpacity), ColorMatrixFlagsDefault, ColorAdjustTypeBitmap);
            CRect rect = CSaverWnd::GetCenterRect(pics[0].img->GetWidth(), pics[0].img->GetHeight());
            int w = rect.Width(); int h = rect.Height();
            g.DrawImage( pics[0].img, Rect(rect.left,rect.top,w,h), 0, 0, w, h, UnitPixel, &ia);
      }
}

void CSlideshow::LoadPics()
{
      if(current_picture == CSaverWnd::picture_names.size()-1) {
            CSaverWnd::picture_names.resize(0);
            CSaverWnd::LoadFileNames(CSaverWnd::search_base, CSaverWnd::picture_names);
            current_picture = -1;
      }
      current_picture++;
      ImageOpacity = 0.0f;
      
      TRACE(_T("Current Pic is... %d, with filename %s\n"), current_picture,CSaverWnd::picture_names[current_picture].c_str());
      USES_CONVERSION;
      bmp = Gdiplus::Bitmap::FromFile( A2W(CSaverWnd::picture_names[current_picture].c_str()),true );
      pics[0].SetPic(bmp);
}
///////////////////////////////////////////////////////////////////////////////////////

The slideshow methods Timer and Paint are called by another external class, which I don't think is relevant. This class also holds a vector of strings representing filenames of images to load. So the idea is Timer is called every few millis, and after a certain period of time (3 seconds here), a new file is loaded. I said, it works fine if I deal straight with the images and don;t put them in an array of CImageResources.

I really do appreciate this help - I'm increasing the points now. Thanks a lot for looking at it.
0
 

Author Comment

by:shifty_mc
ID: 10850288
Points increased
0
 
LVL 19

Accepted Solution

by:
mrwad99 earned 300 total points
ID: 10850356
>>CPlugin::CPlugin(int numberOfElements)
{
     TRACE("In plugin constructor\nInitialising array of pics with %d element(s)\n", numberOfElements);
     CImageResource *pics = new CImageResource[numberOfElements];
}

ARGHHHH !  

Should be

{
     TRACE("In plugin constructor\nInitialising array of pics with %d element(s)\n", numberOfElements);
     pics = new CImageResource[numberOfElements];
}

You were intialising a local variable and not touching the member variable !
0
 

Author Comment

by:shifty_mc
ID: 10850380
Oh , I'm an idiot - the more advanced I try to go, the more I mess up on this kind of stuff, oh well :)

ok, can't tell you how much appreciated your help was - even tho it was that simple I promise you I'd have spent the next 2 days trying to figure it out.

Thanks again
0
 
LVL 19

Expert Comment

by:mrwad99
ID: 10850386
>>Oh , I'm an idiot - the more advanced I try to go, the more I mess up on this kind of stuff, oh well :)

Well I would not say that, but simple mistakes like this are often a pain to see through.  At least you will learn from it.

It has been a pleasure to help you on this.  All the best !
0

Featured Post

The Eight Noble Truths of Backup and Recovery

How can IT departments tackle the challenges of a Big Data world? This white paper provides a roadmap to success and helps companies ensure that all their data is safe and secure, no matter if it resides on-premise with physical or virtual machines or in the cloud.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

  Included as part of the C++ Standard Template Library (STL) is a collection of generic containers. Each of these containers serves a different purpose and has different pros and cons. It is often difficult to decide which container to use and …
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.

809 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question