Page 1 of 2
inc/dec operator return a pointer?
Posted: Thu Sep 20, 2007 8:50 am
by eboyd
Does anyone know if it's possible to overload the increment/decrement operators to return a pointer?
Looking through a lot of documentation it seems they can only return an (int). But i think it would be pretty darned cool if you could write:
as opposed to:
Posted: Thu Sep 20, 2007 9:23 am
by AJ
Hi,
AFAIK, it already happens:
Code: Select all
unsigned long *x = (unsigned long*)myval;
x++;
Assuming a long size of 4 bytes, x will be incremented by 4.
Code: Select all
struct MyStruct *x = (struct MyStruct*)myval;
x++;
Here, x will be incremented by sizeof(struct MyStruct).
Are you actually meaning that you want the same thing to work for a linked list? If so, I don't see why it wouldn't be possible - but I don't know how advisable this would be.
Cheers,
Adam
Posted: Thu Sep 20, 2007 9:26 am
by RedEagle
Hi
outof an german tutorial:
// C++ Kurs
// Beispiel zu ueberladenen Operatoren
// Klassendefinition
class Rect
{
short xPos, yPos; // Position
short width, height; // Breite und Hoehe
public:
Rect(); // ctors
Rect(short x, short y, short w, short h);
Rect operator ++(int); // Verschiebt Rechteck um eine X/Y-Position
};
// Definition der Memberfunktionen
// 1. Konstruktor (Standard Konstruktor)
Rect::Rect()
{
xPos = yPos = width = height = 0;
}
// 2. Konstruktor
// Erhaelt als Parameter die Rechteck-Daten als 4 short Werte
Rect::Rect(short x, short y, short w, short h)
{
xPos = x; yPos = y;
width = w; height = h;
}
// Verschiebt Rechteck um eine X/Y-Position
// Achtung Postfixoperator!
// Darf keine const-Memberfunktion sein da das Objekt
// ja veraendert wird!
Rect Rect::operator ++(int)
{
// Hilfsobjekt zur Aufnahme der akt. Werte
// Ruft copy-ctor auf
Rect orig(*this);
// Nun erst Position veraendern
xPos++;
yPos++;
// Ursprungswerte zurueckgeben
return orig;
}
Posted: Thu Sep 20, 2007 9:46 am
by eboyd
Are you actually meaning that you want the same thing to work for a linked list? If so, I don't see why it wouldn't be possible - but I don't know how advisable this would be.
Yea, I was meaning this. I was thinking that would be an interesting way to handle list traversal. Something like this:
Code: Select all
myClass *curr;
while(curr != something; curr++)
{
// do stuff
}
I've never seen it done that way, so I'm guessing either it's not possible, or not suggested.
Posted: Thu Sep 20, 2007 9:53 am
by eboyd
Rect Rect::operator ++(int)
{
// Hilfsobjekt zur Aufnahme der akt. Werte
// Ruft copy-ctor auf
Rect orig(*this);
// Nun erst Position veraendern
xPos++;
yPos++;
// Ursprungswerte zurueckgeben
return orig;
}
I'm assuming this returns the deep copy of xPos & yPos, but incremented by the postfix increment operator.
But (*this) doesn't return a pointer. I
want a pointer.
In a list class, if you have a next and prev pointers (for traversal purposes mainly) I would like to say p++; and get p = p->next; Or p--; and get p = p->prev;
Posted: Thu Sep 20, 2007 9:58 am
by AJ
OK,
Does
>> this << help?
Cheers,
Adam
Posted: Thu Sep 20, 2007 10:12 am
by eboyd
This compiles:
Code: Select all
node operator++(int)
{
node* curr = curr->next;
return curr;
}
But crashes when I use it:
Code: Select all
void someFuncion()
{
...
curr++;
...
}
Posted: Thu Sep 20, 2007 10:37 am
by Candy
eboyd wrote:This compiles:
Code: Select all
node operator++(int)
{
node* curr = curr->next;
return curr;
}
But crashes when I use it:
Code: Select all
void someFuncion()
{
...
curr++;
...
}
curr is null when you dereference it for next. It's an at that point uninitialized local variable.
Try making a class, say, iterator, that does what you just described.
Code: Select all
#include <list>
#include <iostream>
using std::cout;
using std::endl;
using std::list;
typedef std::list<int>::iterator iterator;
int main() {
list<int> numberlist;
numberlist.push_back(1);
numberlist.push_back(2);
numberlist.push_back(3);
for (iterator i = numberlist.begin(); i != numberlist.end(); ++i) {
cout << *i << endl;
}
}
Analog:
Code: Select all
#include <iostream>
using std::cout;
using std::endl;
int main() {
int numberlist[3] = { 1, 2, 3 };
for (int * i = numberlist; i != numberlist + 3; ++i) {
cout << *i << endl;
}
}
Posted: Thu Sep 20, 2007 12:35 pm
by Solar
It's done easily enough:
Code: Select all
#include <iostream>
class Foo
{
public:
Foo() : mNext( 0 ) {};
Foo( Foo * foo ) : mNext( foo ) {};
Foo * operator++( int ) { return mNext; }
private:
Foo * mNext;
};
int main()
{
Foo x;
Foo y( & x );
std::cout << &x << std::endl;
std::cout << y++ << std::endl;
return 0;
}
However, operator overloading really
should keep the semantics of its native counterparts intact. Look at the example main() - why is x an object, but (y++) a pointer to object? This is pretty easy to get messed up with...
Posted: Thu Sep 20, 2007 1:15 pm
by eboyd
alright, this is basically my class setup:
Code: Select all
template <typename T> class dlist
{
struct type
{
...
T data;
type *next, *prev
...
type* operator++( int ) // for postfix incrementer
};
...
};
The above compiles, but crashes when I use it. Am I declaring it wrong, or in the wrong place?
Why do you return a pointer to an object of class type when you invoke operator++ on an object of class type? What about returning a reference to an object of class type instead?
Ignore the iterator reference, we'll get to that later.
Posted: Thu Sep 20, 2007 3:01 pm
by Solar
eboyd wrote:The above compiles...
I doubt it, since at least two semicolons and an implementation for operator++() are missing. Could you provide some more code, which actually compiles and exhibits the problems you're having?
Posted: Fri Sep 21, 2007 9:42 am
by eboyd
I hope this isn't way too long:
Code: Select all
template < typename T > class dlist
{
public:
dlist() : head( new type( T() ) ), tail( new type( T() ) ) {}
dlist( const dlist& src ) : head( new type( T() ) ), tail( new type( T() ) )
{
clear();
for( type* temp = ( src.head )->next; temp != src.tail; temp = temp->next )
{
pushb( temp->data ) ;
}
}
~dlist()
{
clear();
delete head;
delete tail;
}
/* I've omitted all my member functions to save space here. */
private:
struct type
{
type( const T& x, type* y = 0, type* z = 0 ) : data( x ), prev( y ), next( z ) {}
type( const type& src ) : data( src.data ), prev( src.prev ), next( src.next ) {}
type* operator++( int )
{
return next;
}
T data;
type *prev, *next;
};
type *head, *tail;
};
Here's an example in my defnitions that will cause a crash when called in main():
Code: Select all
/* This simply reverses the order of the list.
*/
template <typename T> void dlist<T>::rev()
{
if(!empty())
{
type* curr = head->next;
int sz = size();
while(curr != tail)
{
T temp = curr->data;
pushf(temp);
curr++; // this is in place of "curr = curr->next"
}
for(int i = 0; i < sz; i++)
{
popb(); // trim the left-over fat
}
}
}
I've also omitted my assignment operators for both "dlist" & "type" to save space since both contain "try-catch" blocks.
I've tried several different versions of the increment operator, most of which compile, but crash when used.
The one in my code here implements your suggestion.
Posted: Sat Sep 22, 2007 3:36 am
by Solar
Does it work when you replace curr++ with curr = curr->next?
Posted: Sat Sep 22, 2007 7:04 am
by eboyd
Does it work when you replace curr++ with curr = curr->next?
Yes, that works. That's how I normally would handle traversal.
But what I'm trying to figure out is if
can do the dame thing as
Posted: Tue Sep 25, 2007 11:56 am
by Candy
eboyd wrote:Does it work when you replace curr++ with curr = curr->next?
Yes, that works. That's how I normally would handle traversal.
But what I'm trying to figure out is if
can do the dame thing as
Yes. But, only if curr is not a pointer or you satisfy other special conditions that a list cannot.
Make curr an object of some type and call operator++ on that object. Curr may not be a pointer.