Board index » cppbuilder » Array of objects

Array of objects


2006-07-24 11:43:43 PM
cppbuilder86
Suppose I have the following :
class TMyObj
{
.......
void __fastcall MyMethod(void);
......
};
.....
.....
TMyObj* MyObj = new TMyObj[100];
At this point I could do the following :
MyObj[37].MyMethod();
How can I, inside the MyMethod routine, know which index (37 in the
example) has been used when dereferencing the pointer ?
Thanks
Alberto
 
 

Re:Array of objects

Quote
class TMyObj
{
.......
void __fastcall MyMethod(void);
......
};
.....
.....
TMyObj* MyObj = new TMyObj[100];

At this point I could do the following :

MyObj[37].MyMethod();

How can I, inside the MyMethod routine, know which index (37 in the
example) has been used when dereferencing the pointer ?

Thanks

Alberto

class TMyObj
{
private:
int FIndex;
.......
void __fastcall MyMethod(void);
.......
public:
__property int Index = {read=FIndex, write=FIndex};
};
TMyObj* MyObj = new TMyObj[100];
for(int i=0; i<100; i++)
MyObj[i].Index = i;
MyObj[37].MyMethod();
Mark
 

Re:Array of objects

"Alberto" < XXXX@XXXXX.COM >wrote in message
Quote
Suppose I have the following :

class TMyObj
{
.......
void __fastcall MyMethod(void);
......
};
.....
.....
TMyObj* MyObj = new TMyObj[100];

At this point I could do the following :

MyObj[37].MyMethod();

How can I, inside the MyMethod routine, know which index (37 in the
example) has been used when dereferencing the pointer ?
The object itself has no way of knowing if it is a standalone object, or if
it is one of several instances in an array. So if you expect the C++
language to provide you with this information, you're out of luck. However,
if MyMethod() is allowed to have access to the MyObj pointer (though it
probably won't), then you could do something like this:
TMyObj::MyMethod(void)
{
int index = this - MyObj;
}
If that isn't acceptable, then you have no choice but to pass the correct
information to the method.
- Dennis
 

{smallsort}

Re:Array of objects

Is this a thought experiment or is there a reason you'd like to know the
index? Mark and Dennis' suggestions are completely valid under the
assumption that you need the index. However, if you can explain your
purpose for requiring the index then maybe another solution will become
apparent.
- Clayton
 

Re:Array of objects

At 17:43:43, 24.07.2006, Alberto wrote:
Quote
Suppose I have the following :

class TMyObj
{
.......
void __fastcall MyMethod(void);
......
};
.....
.....
TMyObj* MyObj = new TMyObj[100];

At this point I could do the following :

MyObj[37].MyMethod();

How can I, inside the MyMethod routine, know which index (37 in the
example) has been used when dereferencing the pointer ?
You can't, except if you explicitly provide a way to pass it to the class
od the method.
MyObj[37]->MyMethod();
If MyObj is global, or at least accessible from the method, you could of
course use a loop to compare "this" with "MyObj[i]".
for (i = 0; i < 100; ++i)
if (this == MyObj[i])
{
index = i;
break;
}
--
Rudy Velthuis [TeamB] rvelthuis.de/
"Luck is the residue of design."
- Branch Rickey - former owner of the Brooklyn Dodger Baseball Team
 

Re:Array of objects

Alberto < XXXX@XXXXX.COM >writes:
Quote
Suppose I have the following :

class TMyObj
{
.......
void __fastcall MyMethod(void);
......
};
.....
.....
TMyObj* MyObj = new TMyObj[100];

At this point I could do the following :

MyObj[37].MyMethod();

How can I, inside the MyMethod routine, know which index (37 in the
example) has been used when dereferencing the pointer ?
Since there is no gurantee that an instance of TMyobj is actually one
in your array, doing pointer arithmetic on it could result in
undefined behavior. You'd need to first determine that "this" is
within the range of Myobj and MyObj+ARRAYSIZE. Then the MyMethod
needs to be able to work even if it's not actually in the array. (Or
you need to prevent it from being instantiated outside the array.)
Another easier solution, without any trickery, is to change the
function slightly, and just tell it the index:
class TMyObj
{
.......
void __fastcall MyMethod(int idx);
......
};
TMyObj* MyObj = new TMyObj[100];
...
int idx = 37;
MyObj[idx].MyMethod(idx);
--
Chris (TeamB);
 

Re:Array of objects

Mark Guerrieri wrote:
Quote
class TMyObj
{
private:
int FIndex;
.......
void __fastcall MyMethod(void);
.......

public:
__property int Index = {read=FIndex, write=FIndex};
};

TMyObj* MyObj = new TMyObj[100];
for(int i=0; i<100; i++)
MyObj[i].Index = i;

MyObj[37].MyMethod();
Thanks to all who answered, and, yes, maybe the fastest and simplest
solution is to have a private member that stores the index, accessed
then by the MyMethod routine.
The reason why I need this is simple. The objects are TImage(s), and
each of them has a bitmap which is the photo of a single-digit number. I
want a way to increment the number represented by the totality of the
images, placed contiguously. So, if I increment the Nth element of the
array, and the digit reaches 9, I need to increment the element of the
array on the left (i.e. the N-1 th element), and so on for other
arithmetic operations.
Thanks,
Alberto
 

Re:Array of objects

"Alberto" < XXXX@XXXXX.COM >wrote in message
Quote
The reason why I need this is simple. The objects are TImage(s), and
each of them has a bitmap which is the photo of a single-digit number.
I want a way to increment the number represented by the totality of the
images, placed contiguously. So, if I increment the Nth element of the
array, and the digit reaches 9, I need to increment the element of the
array on the left (i.e. the N-1 th element)
All VCL components have a published Tag property available. You can store
the current numeric value of each image in that property, and then loop
through your array when needed. For example:
private:
TImage* FImages[100];
__fastcall TForm1::TForm1(TComponent *Owner)
: TForm(Owner)
{
for(int i = 0; i < 100; ++i)
{
FImages[i] = new TImage(this);
FImages[i]->Parent = this;
// set other properties as needed ...
FImages[i]->LoadFromFile("0.bmp");
}
}
void __fastcall TForm1::Increment(int Index)
{
if( (Index>= 0) && (Index < 100) )
{
FImages[Index]->Tag = FImages[Index]->Tag + 1;
if( FImages[Index]->Tag>9 )
{
FImages[Index]->Tag = 0;
Increment(Index-1);
}
FImages[Index]->Picture->LoadFromFile(AnsiString(FImages[Index]->Tag) +
".bmp");
}
}
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Increment(99);
}
Quote
and so on for other arithmetic operations.
I would not recommend doing arithmetic operations on the individual digs.
You should store the total numeric value as an integer, and perform your
operations on it normally, and then simply update the images to display
whenever the current numeric value is. For example:
private:
TImage* FImages[10];
int FCurrentValue;
void __fastcall SetCurrentValue(int NewValue);
__fastcall TForm1::TForm1(TComponent *Owner)
: TForm(Owner)
{
for(int i = 0; i < 10; ++i)
{
FImages[i] = new TImage(this);
FImages[i]->Parent = this;
// set other properties as needed ...
FImages[i]->LoadFromFile("0.bmp");
}
}
void __fastcall TForm1::SetCurrentValue(int NewValue)
{
if( NewValue < 0 )
NewValue = 0;
if( FCurrentValue != NewValue )
{
FCurrentValue = NewValue;
for(int i = 9; i>= 0; --i)
{
FImages[i]->Tag = NewValue % 10;
FImages[i]->Picture->LoadFromFile(AnsiString(FImages[i]->Tag) + ".bmp");
NewValue /= 10;
}
}
}
void __fastcall TForm1::Button1Click(TObject *Sender)
{
SetCurrentValue(FCurrentValue + 100);
Update();
Sleep(1000);
SetCurrentValue(FCurrentValue * 255);
Update();
Sleep(1000);
SetCurrentValue(FCurrentValue / 360);
Update();
Sleep(1000);
// etc...
}
Gambit
 

Re:Array of objects

Remy Lebeau (TeamB) wrote:
Quote
I would not recommend doing arithmetic operations on the individual digs.
You should store the total numeric value as an integer, and perform your
operations on it normally, and then simply update the images to display
whenever the current numeric value is. For example:

Yes, I totally agree that that is the correct way to proceed, but this
case is special... the user can hover the mouse over any single digit,
and rotating the mouse wheel he can increase or decrease it. So I found
easier manipulating the digits themselves, changing on the fly the
bitmap that shows the digit (using an image list), and computing the
numeric value from the set of images shown, and not the other way around.
Thanks for the suggestions, in the last hour I implemented it and,
guess... it works...:-)
Alberto
 

Re:Array of objects

At 19:17:22, 24.07.2006, Chris Uzdavinis (TeamB) wrote:
Quote
int idx = 37;
MyObj[idx].MyMethod(idx);
That is the cleanest approach, IMO.
--
Rudy Velthuis [TeamB] rvelthuis.de/
"It is better to be feared than loved, if you cannot be both."
- Niccolo Machiavelli (1469-1527), "The Prince"
 

Re:Array of objects

"Alberto" < XXXX@XXXXX.COM >wrote in message
Quote
Yes, I totally agree that that is the correct way to proceed, but this
case is special... the user can hover the mouse over any single digit,
and rotating the mouse wheel he can increase or decrease it.
Ok then. You can still do that, while still maintaining the numeric value
in an integer variable for arithmetic purposes. Each time a single digit is
changed, simply update the variable accordingly. You can merge my earlier
two code snippets together, for example (untested):
struct TDigit
{
int Index;
int Value;
TImage *Image;
};
__published:
void __fastcall ImageMouseWheelDown(TObject* Sender, TShiftState
Shift, const TPoint &MousePos, bool &Handled);
void __fastcall ImageMouseWheelUp(TObject* Sender, TShiftState
Shift, const TPoint &MousePos, bool &Handled);
void __fastcall Button1Click(TObject *Sender);
private:
TDigit FDigits[10];
int FCurrentValue;
void __fastcall DecrementDigit(TDigit *Digit);
void __fastcall IncrementDigit(TDigit *Digit);
void __fastcall SetCurrentValue(int NewValue);
void __fastcall UpdateCurrentValue();
__fastcall TForm1::TForm1(TComponent *Owner)
: TForm(Owner)
{
for(int i = 0; i < 10; ++i)
{
FDigits[i].Index = i;
FDigits[i].Value = 0;
FDigits[i].Image = new TImage(this);
FDigits[i].Image->Parent = this;
// set other properties as needed ...
FDigits[i].Image->Tag = reinterpret_cast<int>(&FDigits[i]);
FDigits[i].Image->OnMouseWheelDown = ImageMouseWheelDown;
FDigits[i].Image->OnMouseWheelUp = ImageMouseWheelUp;
ImageList1->GetBitmap(0, FDigits[i].Image->Picture->Bitmap);
}
}
void __fastcall TForm1::DecrementDigit(TDigit *Digit)
{
Digit->Value--;
if( Digit->Value < 0 )
{
Digit->Value = 9;
if( Digit->Index>0 )
DecrementDigit(&FDigits[Digit->Index-1]);
}
ImageList1->GetBitmap(Digit->Value, Digit->Image->Picture->Bitmap);
Digit->Image->Invalidate();
}
void __fastcall TForm1::IncrementDigit(TDigit *Digit)
{
Digit->Value++;
if( Digit->Value>9 )
{
Digit->Value = 0;
if( Digit->Index>0 )
IncrementDigit(&FDigits[Digit->Index-1]);
}
ImageList1->GetBitmap(Digit->Value, Digit->Image->Picture->Bitmap);
Digit->Image->Invalidate();
}
void __fastcall TForm1::SetCurrentValue(int NewValue)
{
if( NewValue < 0 )
NewValue = 0;
if( FCurrentValue != NewValue )
{
FCurrentValue = NewValue;
for(int i = 9; i>= 0; --i)
{
FDigits[i].Value = NewValue % 10;
NewValue /= 10;
ImageList1->GetBitmap(FDigits[i].Value,
FDigits[i].Image->Picture->Bitmap);
FDigits[i].Image->Invalidate();
}
}
}
void __fastcall TForm1::UpdateCurrentValue()
{
__int64 NewValue = 0;
int Multiplier = 1;
for(int i = 9; i>= 0; --i)
{
NewValue += (FDigits[i].Value * Multiplier);
Multiplier *= 10;
}
if( NewValue <= MaxInt )
FCurrentValue = NewValue;
else
SetCurrentValue(MaxInt);
}
void __fastcall TForm1::ImageMouseWheelDown(TObject* Sender, TShiftState
Shift, const TPoint &MousePos, bool &Handled)
{
TImage *pImage = dynamic_cast<TImage*>(Sender);
if( pImage )
{
DecrementDigit(reinterpret_cast<TDigit*>(pImage->Tag));
UpdateCurrentValue();
Handled = true;
}
}
void __fastcall TForm1::ImageMouseWheelUp(TObject* Sender, TShiftState
Shift, const TPoint &MousePos, bool &Handled)
{
TImage *pImage = dynamic_cast<TImage*>(Sender);
if( pImage )
{
IncrementDigit(reinterpret_cast<TDigit*>(pImage->Tag));
UpdateCurrentValue();
Handled = true;
}
}
void __fastcall TForm1::Button1Click(TObject *Sender)
{
SetCurrentValue(1234567890);
}
Gambit
 

Re:Array of objects

Gambit,
thanks for the code snippet, I have only one problem with it, which
should be simple to solve, but I need some guidance.
The component TImage does not expose the OnMouseWheelDown or
OnMouseWheelUp events. They are protected events of TControl.
How can I make them accessible ?
Thanks
Alberto
----------------------------
Remy Lebeau (TeamB) wrote:
Quote
FDigits[i].Image->OnMouseWheelDown = ImageMouseWheelDown;
FDigits[i].Image->OnMouseWheelUp = ImageMouseWheelUp;

 

Re:Array of objects

"Alberto" < XXXX@XXXXX.COM >wrote in message
Quote
The component TImage does not expose the OnMouseWheelDown
or OnMouseWheelUp events. They are protected events of TControl.
How can I make them accessible ?
Derive a new class from TImage and promote the events to public.
If that does not work, then you can assign a handler to the
TApplication::OnMessage event and handle the wheel messages directly.
Gambit