++ Operator Overloading

Please support our C++ advertiser: Intel Parallel Studio Home
Reply

Join Date: Feb 2008
Posts: 67
Reputation: c++noobie is an unknown quantity at this point 
Solved Threads: 1
c++noobie c++noobie is offline Offline
Junior Poster in Training

++ Operator Overloading

 
0
  #1
Jan 7th, 2009
I am trying to overload operator++ for a type I have defined. Here' s a little explanation beforehand.
I am working on a link_list class that can be used to create dynamic arrays of any type. I created a basic_link template to hold each element of the array. Each basic_link contains<T> contains a pointer to the next link, the previous link, and a variable to hold a T value. It looks something like this
  1. template <typename T>
  2. struct basic_link
  3. {
  4. T value;
  5. basic_link<T> *previous, *next;
  6. // Definitions of constructors and operators and such
  7. }
I then have a basic_list template that contains two basic_list pointers to the first and last (head and tail) elements of the array and a size variable. I have two typedefs in the class. It looks a little like this
  1. template <typename T>
  2. class basic_list
  3. {
  4. typedef basic_link<T> link;
  5. typedef link* iterator;
  6.  
  7. iterator head, tail;
  8. size_t size;
  9. // Further class definition
  10. }

I am trying to make it so that iterator++ causes the iterator to become iterator->next. This is what I tried
  1. friend const iterator& operator++ ( iterator& _iter )
  2. {
  3. _iter= _iter->next;
  4. return _iter;
  5. }
Any help you may can offer would be greatly appreciated.
Reply With Quote Quick reply to this message  
Join Date: Jul 2008
Posts: 2,001
Reputation: ArkM has much to be proud of ArkM has much to be proud of ArkM has much to be proud of ArkM has much to be proud of ArkM has much to be proud of ArkM has much to be proud of ArkM has much to be proud of ArkM has much to be proud of ArkM has much to be proud of 
Solved Threads: 343
ArkM's Avatar
ArkM ArkM is offline Offline
Postaholic

Re: ++ Operator Overloading

 
0
  #2
Jan 7th, 2009
As usually, a container iterator is not typedef only, it's a class.
It seems your solution have at least two defects (apart from incorrect syntax):
1. Your list container users want LIST abstraction, not LIST NODE one.
2. It's a class declares some classes or ordinar functions as friends, a function can't proclaim herself as a friend.
Look at some C++ iterator tutorials:
http://sourcemaking.com/design_patterns/iterator/c++/1
http://www.oreillynet.com/pub/a/netw...us.html?page=1
then try again
Reply With Quote Quick reply to this message  
Join Date: Feb 2008
Posts: 67
Reputation: c++noobie is an unknown quantity at this point 
Solved Threads: 1
c++noobie c++noobie is offline Offline
Junior Poster in Training

Re: ++ Operator Overloading

 
0
  #3
Jan 7th, 2009
Thanks a lot for your help, this clears things up quite a bit. I've started working on a basic_link iterator, I am trying to implement some operators, and I am not sure of an effective way to implement the -> operator or comparison operators (>, <, >=, <=).
Reply With Quote Quick reply to this message  
Join Date: Feb 2008
Posts: 67
Reputation: c++noobie is an unknown quantity at this point 
Solved Threads: 1
c++noobie c++noobie is offline Offline
Junior Poster in Training

Re: ++ Operator Overloading

 
0
  #4
Jan 7th, 2009
Another quick question. I have a begin() function that returns the head of the list, but I cannot reference it when I try to call it from another list that came into the current list as an argument e.g.
  1. iterator begin()
  2. {
  3. return head;
  4. }
  5. list& append( const list &_list )
  6. {
  7. for( iterator position = _list.head; !position.null(); position++ )
  8. this->append(*position.element);
  9. return *this;
  10. }
The above append function works fine using _list.head, but I cannot use a call to _list.begin(). I'm thinking it's because I'm accepting it as a const list and then trying to call something from it. I was trying to use const list& to avoid the overhead of creating another copy of the list. What would be the best course of action here? Leave it as it is or try to change it up somehow?
Last edited by c++noobie; Jan 7th, 2009 at 4:14 pm.
Reply With Quote Quick reply to this message  
Join Date: Jul 2008
Posts: 2,001
Reputation: ArkM has much to be proud of ArkM has much to be proud of ArkM has much to be proud of ArkM has much to be proud of ArkM has much to be proud of ArkM has much to be proud of ArkM has much to be proud of ArkM has much to be proud of ArkM has much to be proud of 
Solved Threads: 343
ArkM's Avatar
ArkM ArkM is offline Offline
Postaholic

Re: ++ Operator Overloading

 
0
  #5
Jan 7th, 2009
Post the code, it's impossible to answer without class List definition. You define list node only in the original post. No a list and a list iterator complete definitions till now.
Reply With Quote Quick reply to this message  
Join Date: Nov 2007
Posts: 390
Reputation: skatamatic will become famous soon enough skatamatic will become famous soon enough 
Solved Threads: 39
skatamatic skatamatic is offline Offline
Posting Whiz

Re: ++ Operator Overloading

 
0
  #6
Jan 7th, 2009
I don't think the -> operator (or the . or & operator) can be overloaded =(
Reply With Quote Quick reply to this message  
Join Date: Feb 2008
Posts: 67
Reputation: c++noobie is an unknown quantity at this point 
Solved Threads: 1
c++noobie c++noobie is offline Offline
Junior Poster in Training

Re: ++ Operator Overloading

 
0
  #7
Jan 7th, 2009
Ok, I'm sorry this is so long, but you did ask for my code.
BTW, I'm running this with the default gcc compiler that comes with the binary release of the codeblocks IDE.
  1. #ifndef _LIST
  2. #define _LIST
  3.  
  4. #ifndef _LINK
  5. #include "link.h"
  6. #endif
  7.  
  8. #ifndef _GLIBCXX_IOSTREAM
  9. #include <iostream>
  10. #endif
  11.  
  12. #ifndef __EXCEPTION__
  13. #include <exception>
  14. #endif
  15.  
  16. class iteratorexception: public std::exception
  17. {
  18. virtual const char* what() const throw()
  19. {
  20. return "Bad iterator reference (iterator was NULL)";
  21. }
  22. } nulliterator;
  23.  
  24. class indexexception: public std::exception
  25. {
  26. virtual const char* what() const throw()
  27. {
  28. return "Error, the index was out of range";
  29. }
  30. } badindex;
  31.  
  32. template <typename T>
  33. class basic_list
  34. {
  35. typedef basic_link<T> link;
  36. typedef basic_list<T> list;
  37. typedef link* plink;
  38.  
  39. plink head, tail;
  40. size_t size;
  41.  
  42. public:
  43. class iterator;
  44. const static size_t npos= -1;
  45.  
  46. basic_list()
  47. : head(NULL), tail(NULL), size(0)
  48. {}
  49.  
  50. basic_list( const T &_value )
  51. : head(new link(_value)), tail(head), size(1)
  52. {}
  53.  
  54. basic_list( const link &_link )
  55. : head(new link(_link.value)), tail(head), size(1)
  56. {}
  57.  
  58. basic_list( const list &_list )
  59. : head(NULL), tail(NULL), size(0)
  60. {
  61. for( iterator position = _list.head; !position.null(); position++ )
  62. this->append(*position);
  63. }
  64.  
  65. ~basic_list()
  66. {
  67. iterator position (head);
  68. while( !position.null() )
  69. {
  70. delete position++.element;
  71. }
  72. }
  73.  
  74. // Data methods
  75. iterator begin()
  76. {
  77. iterator iter(head);
  78. return iter;
  79. }
  80. iterator end()
  81. {
  82. iterator iter(tail);
  83. return iter;
  84. }
  85.  
  86. const char* type() { return typeid(T).name(); }
  87. bool empty() { return ( this->size == 0 ); }
  88. size_t length() { return this->size; }
  89.  
  90. // Modifier methods
  91. list& clear()
  92. {
  93. iterator position (head);
  94. while( !position.null() )
  95. {
  96. delete position++.element;
  97. }
  98.  
  99. head= tail= NULL;
  100. size= 0;
  101.  
  102. return *this;
  103. }
  104.  
  105. void swap( list &_list )
  106. {
  107. list temp(_list);
  108. _list.assign(*this);
  109. this->assign(temp);
  110. }
  111.  
  112. // Assignment methods
  113. list& assign( list _list )
  114. {
  115. this->clear();
  116. this->append(_list);
  117. return *this;
  118. }
  119. list& assign( list _list, size_t _pos, size_t _n= npos )
  120. {
  121. this->clear();
  122. try
  123. {
  124. this->append(_list.sublist( _pos, _n ));
  125. }
  126. catch( std::exception &e )
  127. {
  128. throw e;
  129. }
  130. return *this;
  131. }
  132. list& assign( size_t _n, const T &_value )
  133. {
  134. this->clear();
  135. for( size_t i = 0; i < _n; i++ )
  136. this->append(_value);
  137. return *this;
  138. }
  139. list& assign( size_t _n, const link &_link )
  140. {
  141. this->clear();
  142. for( size_t i = 0; i < _n; i++ )
  143. this->append(_link.value);
  144. return *this;
  145. }
  146. list& assign( iterator _first, iterator _last )
  147. {
  148. this->clear();
  149. iterator current= _first, end= _last+1; // _last+1 to include the _last
  150. while( !current.null() && current != end )
  151. this->append(*current++);
  152. return*this;
  153. }
  154.  
  155. // Insertion methods
  156. list& insert( size_t _pos, const T &_value )
  157. {
  158. if( _pos >= size )
  159. throw badindex;
  160. plink position= &this->at(_pos);
  161. plink new_link= new link( _value, position->previous, position );
  162. if( position == head )
  163. head= position->previous= new_link;
  164. else
  165. position->previous= position->previous->next= new_link;
  166. return *this;
  167. }
  168. list& insert( size_t _pos, const link &_link )
  169. {
  170. if( _pos >= size )
  171. throw badindex;
  172. plink position= &this->at(_pos);
  173. plink new_link= new link( _link.value, position->previous, position );
  174. if( position == head )
  175. head= position->previous= new_link;
  176. else
  177. position->previous= position->previous->next= new_link;
  178. return *this;
  179. }
  180. list& insert( size_t _pos, size_t _n, const T &_value )
  181. {
  182. if( _pos >= size )
  183. throw badindex;
  184. for( size_t i = 0; i < _n; i++ )
  185. this->append( _pos, _value );
  186. return *this;
  187. }
  188. list& insert( size_t _pos, size_t _n, const link &_link )
  189. {
  190. if( _pos >= size )
  191. throw badindex;
  192. T _value= _link.value;
  193. for( size_t i = 0; i < _n; i++ )
  194. this->append( _pos, _value );
  195. return *this;
  196. }
  197. list& insert( size_t _pos, const list &_list )
  198. {
  199. if( _pos >= size )
  200. throw badindex;
  201. for( iterator position = _list.head; !position.null(); position++, _pos++ )
  202. this->insert( _pos, *position );
  203. return *this;
  204. }
  205. list& insert( size_t _pos1, list _list, size_t _pos2, size_t _n= npos )
  206. {
  207. if( _pos1 >= size )
  208. throw badindex;
  209. try
  210. {
  211. this->insert( _pos1, _list.sublist( _pos2, _n ) );
  212. }
  213. catch( std::exception &e )
  214. {
  215. throw e;
  216. }
  217. return *this;
  218. }
  219.  
  220. // Appending methods
  221. list& append( const T &_value )
  222. {
  223. plink new_link= new link(_value, tail);
  224. if( size == 0 )
  225. tail= head= new_link;
  226. else
  227. tail= tail->next= new_link;
  228. size++;
  229. return *this;
  230. }
  231. list& append( const link &_link )
  232. {
  233. plink new_link= new link(_link.value, tail);
  234. if( size == 0 )
  235. tail= head= new_link;
  236. else
  237. tail= tail->next= new_link;
  238. size++;
  239. return *this;
  240. }
  241. list& append( const list &_list )
  242. {
  243. iterator position= _list.head;
  244. size_t count= _list.size;
  245. for( size_t i = 0; i < count; i++ )
  246. this->append(*position++);
  247. return *this;
  248. }
  249. list& operator+= ( const T &_value )
  250. {
  251. plink new_link= new link(_value, tail);
  252. if( size == 0 )
  253. tail= head= new_link;
  254. else
  255. tail= tail->next= new_link;
  256. size++;
  257. return *this;
  258. }
  259. list& operator+= ( const link &_link )
  260. {
  261. plink new_link= new link(_link.value, tail);
  262. if( size == 0 )
  263. tail= head= new_link;
  264. else
  265. tail= tail->next= new_link;
  266. size++;
  267. return *this;
  268. }
  269. list& operator+= ( const list _list )
  270. {
  271. for( iterator position = _list.head; !position.null(); position++ )
  272. this->append(*position);
  273. return *this;
  274. }
  275.  
  276. // Access Methods
  277. link& at( size_t _pos )
  278. {
  279. if( _pos >= size )
  280. throw badindex;
  281. iterator position(head);
  282. return *(position+_pos);
  283. }
  284. link& operator[] ( size_t _pos )
  285. {
  286. if( _pos >= size )
  287. throw badindex;
  288. iterator position(head);
  289. return *(position+_pos);
  290. }
  291.  
  292. // Operation methods
  293. size_t find( const T &_value, size_t _pos )
  294. {
  295. if( _pos >= size )
  296. throw badindex;
  297. iterator position(&this->at(_pos));
  298. while( !position.null() && _value != *position++ )
  299. if( *position == _value )
  300. return _pos;
  301. else
  302. _pos++;
  303. return npos;
  304. }
  305. size_t find( const link &_link, size_t _pos )
  306. {
  307. if( _pos >= size )
  308. throw badindex;
  309. iterator position(&this->at(_pos));
  310. while( !position.null() && _link.value != *position++ )
  311. if( *position == _link.value )
  312. return _pos;
  313. else
  314. _pos++;
  315. return npos;
  316. }
  317.  
  318. list sublist( size_t _pos, size_t _n= npos )
  319. {
  320. if( _pos >= size )
  321. throw badindex;
  322. list temp;
  323. iterator position(&this->at(_pos));
  324. for( size_t i = 0; i < npos && !position.null(); i++, position++ )
  325. temp.append(*position);
  326. return temp;
  327. }
  328.  
  329. // Output method
  330. template <typename CharT>
  331. friend std::basic_ostream<CharT>& operator<< ( std::basic_ostream<CharT> &out, const list &_list )
  332. {
  333. if( _list.size > 0 )
  334. {
  335. out << "{ ";
  336. iterator start(_list.head), end(_list.tail);
  337. for( iterator position= start; !position.null(); position++ )
  338. {
  339. if( typeid(T) == typeid(char) )
  340. out << '\'' << *position << '\'';
  341. else if( typeid(T) == typeid(char*) || typeid(T) == typeid(std::string) )
  342. out << '\"' << *position << '\"';
  343. else
  344. out << *position;
  345. out << ( position != end ? ", " : " }" );
  346. }
  347. }
  348. return out;
  349. }
  350. };
  351.  
  352. template <typename T>
  353. struct basic_list<T>::iterator
  354. {
  355. plink element;
  356.  
  357. // Constructors
  358. iterator()
  359. : element(NULL)
  360. {}
  361.  
  362. iterator( plink _link )
  363. : element(_link)
  364. {}
  365.  
  366. iterator( const iterator &_iter )
  367. : element(_iter.element)
  368. {}
  369.  
  370. bool null() { return ( this->element == NULL ); }
  371.  
  372. // Operators
  373.  
  374. link& operator* ()
  375. {
  376. if( element == NULL )
  377. throw nulliterator;
  378. return *element;
  379. }
  380. // Problem, find out how to declare operator->
  381. // operator-> ()
  382.  
  383. link& operator[] ( size_t _offset )
  384. {
  385. if( element == NULL )
  386. throw nulliterator;
  387. iterator temp(*this);
  388. for( size_t i = 0; i < _offset; i++ )
  389. {
  390. if( temp.element == NULL )
  391. throw nulliterator;
  392. temp.element= temp.element->next;
  393. }
  394. return *temp.element;
  395. }
  396.  
  397. bool operator== ( const iterator &_iter ) { return ( this->element == _iter.element ); }
  398. bool operator!= ( const iterator &_iter ) { return ( this->element != _iter.element ); }
  399. bool operator== ( const plink _link ) { return ( this->element == _link ); }
  400. bool operator!= ( const plink _link ) { return ( this->element != _link ); }
  401.  
  402. iterator operator+ ( const size_t &_n )
  403. {
  404. iterator temp(*this);
  405. for( size_t i = 0; i < _n; i++ )
  406. {
  407. if( temp.element == NULL )
  408. throw nulliterator;
  409. temp.element= temp.element->next;
  410. }
  411. return temp;
  412. }
  413. iterator operator- ( const size_t &_n )
  414. {
  415. iterator temp(*this);
  416. for( size_t i = 0; i < _n; i++ )
  417. {
  418. if( temp.element == NULL )
  419. throw nulliterator;
  420. temp.element= temp.element->previous;
  421. }
  422. return temp;
  423. }
  424.  
  425. iterator& operator+= ( const size_t &_n )
  426. {
  427. for( size_t i = 0; i < _n; i++ )
  428. {
  429. if( this->element == NULL )
  430. throw nulliterator;
  431. this->element= this->element->next;
  432. }
  433. return *this;
  434. }
  435. iterator& operator-= ( const size_t &_n )
  436. {
  437. for( size_t i = 0; i < _n; i++ )
  438. {
  439. if( this->element == NULL )
  440. throw nulliterator;
  441. this->element= this->element->previous;
  442. }
  443. return *this;
  444. }
  445.  
  446. iterator& operator= ( const iterator &_iter )
  447. {
  448. this->element= _iter.element;
  449. return *this;
  450. }
  451. iterator& operator= ( link *_link )
  452. {
  453. this->element= _link;
  454. return *this;
  455. }
  456.  
  457. iterator& operator++ ()
  458. {
  459. if( element == NULL )
  460. throw nulliterator;
  461. element= element->next;
  462. return *this;
  463. }
  464. iterator operator++ ( int )
  465. {
  466. if( element == NULL )
  467. throw nulliterator;
  468. iterator current (*this);
  469. element= element->next;
  470. return current;
  471. }
  472.  
  473. iterator& operator-- ()
  474. {
  475. if( element == NULL )
  476. throw nulliterator;
  477. element= element->previous;
  478. return *this;
  479. }
  480. iterator operator-- ( int )
  481. {
  482. if( element == NULL )
  483. throw nulliterator;
  484. iterator current (*this);
  485. element= element->previous;
  486. return current;
  487. }
  488.  
  489. /*void* operator new ( size_t size)
  490. {
  491. this->element= new link
  492. }
  493.  
  494. void operator delete (void *p)
  495. {
  496. free(p);
  497. }*/
  498. };
  499.  
  500. typedef basic_list<int> intlist;
  501. typedef basic_list<double> doublelist;
  502. typedef basic_list<char> charlist;
  503. typedef basic_list<bool> boollist;
  504. #ifdef _GLIBCXX_STRING
  505. typedef basic_list<std::string> stringlist;
  506. #define slist stringlist
  507. #define strlist stringlist
  508. #endif
  509. #define ilist intlist
  510. #define dlist doublelist
  511. #define dbllist doublelist
  512. #define clist charlist
  513. #define blist boollist
  514.  
  515. #endif /* _LINK */

One thing I would like to figure out, but can't quite figure out. I want to overload the -> operator on the iterator class to be able to reference the members of the list (i.e. iterator->next, iterator->previous, and iterator->value). I also still have no idea where to go with the comparison operators.

Originally Posted by skatamatic View Post
I don't think the -> operator (or the . or & operator) can be overloaded =(
I'm not 100% sure it can, but I thought it could. I have seen some stuff about overloading the -> operator, I just don't quite understand it.
Last edited by c++noobie; Jan 7th, 2009 at 11:46 pm.
Reply With Quote Quick reply to this message  
Join Date: Jul 2008
Posts: 2,001
Reputation: ArkM has much to be proud of ArkM has much to be proud of ArkM has much to be proud of ArkM has much to be proud of ArkM has much to be proud of ArkM has much to be proud of ArkM has much to be proud of ArkM has much to be proud of ArkM has much to be proud of 
Solved Threads: 343
ArkM's Avatar
ArkM ArkM is offline Offline
Postaholic

Re: ++ Operator Overloading

 
0
  #8
Jan 8th, 2009
Regrettably you forgot to present list.h so I've invented my own complete list_node type to compile your code. The base_list template member functions used class iterator objects so you must insert class iterator definition in the base_list body, incomplete class (why struct? ) declaration is insufficient.
  1. template <typename T>
  2. class basic_list
  3. { ...
  4. friend class iterator;
  5. class iterator
  6. {
  7. ...
  8. };
  9. ...
  10. };
Correct base_list destructor: class base_list can't access private element member of basic_node (may be you did that at the true list.h).

No need to declare base_list<T>::iterator as a template.

After that try to debug the code. I think, there are lots of errors in base_list and iterator logics, it's a common case.

Alas, I don't like these classes design very much:
1. C++ Standard:
Iterators are a generalization of pointers that allow a C++ program to work with different data structures (containers) in a uniform manner.
...
All iterators i support the expression *i, resulting in a value of some class, enumeration, or built-in type T, called the value type of the iterator. All iterators i for which the expression (*i).m is well-defined, support the expression i->m with the same semantics as (*i).m. For every iterator type X for which equality is defined, there is a corresponding signed integral type called the difference type of the iterator.
Since iterators are an abstraction of pointers, their semantics is a generalization of most of the semantics of pointers in C + +.
However you "iterator" returns link object (not base_list value type) and does not support operator -> at all.
More info: http://www.oreillynet.com/pub/a/netw...us.html?page=2
2. Your base_list<T> is not a list of T elements. It's a list of nodes. This C-like approach transmute this "yet another linked list" class into some kind of caricature on C++ container and container iterator concepts. It's a container-exhibitionist, it exposes its own internals (list nodes and other list support structures) outside. It's a rather strange (and incomplete) chimere of std::vector and C-like double linked list.

Of course, that's your affairs, not mine. I'm a potential user of these classes only but I don't want such list containers in my codes. The worst thing is that you can't study simple, clear and useful C++ container/iterator concepts on this base...

Oh, I forgot to answer your last question about begin() member function. The point is that a natural container.begin() must return referencable iterator to the 1st real node (not at list head - internal list structure). Apropos, container.end() must return unreferencable iterator "past-the-end" of list.
Reply With Quote Quick reply to this message  
Join Date: Feb 2008
Posts: 67
Reputation: c++noobie is an unknown quantity at this point 
Solved Threads: 1
c++noobie c++noobie is offline Offline
Junior Poster in Training

Re: ++ Operator Overloading

 
0
  #9
Jan 10th, 2009
Thank you for all of your input. I basically started this whole project to try and do a little learning by experience with class relationships, dynamic memory management, and found a new topic to learn about in the process (iterators). I really had no idea where to start so I took a topic that was briefly referenced in a programming class (link lists) and tried to expand on it. Apparently I missed the target and began writing some ineffective and ugly classes. Do you have any suggestions for a better way to try to deepen my understanding for these topics? (BTW thanks again for all of your help thusfar)
Reply With Quote Quick reply to this message  
Reply

This thread is more than three months old.
Perhaps start a new thread instead?
Message:


Thread Tools Search this Thread



About Us | Contact Us | Advertise | DaniWeb | Acceptable Use Policy | RSS Feed

©2003 - 2009 DaniWeb® LLC