Solved

Simple question on pointers and classes that hold pointers

Posted on 2004-04-17
21
401 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
Comment Utility
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
Comment Utility
>> 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
Comment Utility
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
 
LVL 19

Expert Comment

by:mrwad99
Comment Utility
>> 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
Comment Utility
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
Comment Utility
sorry - should have said - I did add the code
this->img = NULL;
in the CImageResource constructor
0
 
LVL 9

Expert Comment

by:Cayce
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

 

Author Comment

by:shifty_mc
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
Points increased
0
 
LVL 19

Accepted Solution

by:
mrwad99 earned 300 total points
Comment Utility
>>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
Comment Utility
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
Comment Utility
>>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

Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

  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 …
Introduction This article is a continuation of the C/C++ Visual Studio Express debugger series. Part 1 provided a quick start guide in using the debugger. Part 2 focused on additional topics in breakpoints. As your assignments become a little more …
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.

744 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

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now