24

I'm trying to iterate through a Players hand of cards.

#include <vector>
#include <iostream>

class Card {
  int card_colour, card_type;
public:
  std::string display_card();
};

std::string Card::display_card(){
  std::stringstream s_card_details;
  s_card_details << "Colour: " << card_colour << "\n";
  s_card_details << "Type: " << card_type << "\n";
    
  return s_card_details.str();
}

int main() 
{
  std::vector<Card*>current_cards;
  vector<Card*>::iterator iter;
  for(iter = current_cards.begin(); iter != current_cards.end(); iter++) 
  {
    std::cout << iter->display_card() << std::endl;
  }
}

This line

std::cout << iter->display_card() << std::endl;

currently comes up with the

error: Expression must have pointer-to-class type.

How can I fix this?

Nathan Pierson
  • 5,461
  • 1
  • 12
  • 30
Red Shift
  • 1,312
  • 2
  • 17
  • 29

4 Answers4

40

Try this:

cout << (*iter)->display_card() << endl;

The * operator gives you the item referenced by the iterator, which in your case is a pointer. Then you use the -> to dereference that pointer.

Reto Koradi
  • 53,228
  • 8
  • 93
  • 133
5

You have to dereference the iterator to access the pointer:

#include <vector>
#include <iostream>

class Card {
public:
  std::string display_card();
};


int main() {
  std::vector<Card*>current_cards;
  std::vector<Card*>::iterator iter, end;
  for(iter = current_cards.begin(), end = current_cards.end() ; iter != end; ++iter) {
    std::cout << (*iter)->display_card() << std::endl;
  }
}

Another observation is the iter++ which you should avoid in profit of ++iter (see https://stackoverflow.com/a/24904/2077394). Depending on the container, you may also want to avoid calling end() each iteration.

cigien
  • 57,834
  • 11
  • 73
  • 112
Joky
  • 1,608
  • 11
  • 15
2

De-referencing the iterator by iter-> gives a pointer to an object of type Card, you have to write (*iter)->display_card();

cigien
  • 57,834
  • 11
  • 73
  • 112
Rakib
  • 7,435
  • 7
  • 29
  • 45
1

An alternative to using (*iter)-> is to pre-emptively dereference the iterator with range-based for.

std::vector<Card*> current_cards;
// Code that populates current_cards goes here...

for(auto p_card : current_cards)
{
    std::cout << p_card->display_card() << std::endl;
}

In the above code, p_card is already a Card* pointer instead of a std::vector<Card*>::iterator iterator. To me this is clearer than the version that explicitly dereferences the iterator and then dereferences the pointer, and is certainly more concise. It also means I don't have to worry about operator precedence pitfalls with -> and unary *.

Nathan Pierson
  • 5,461
  • 1
  • 12
  • 30