views:

70

answers:

3

I had an exam yesterday for Programming I at the end of my first semester. It was pretty basic, except I made a really, really obscure mistake that I wanted to ask the more experienced people here about:

I basically had a class Library that contained a vector that contains elements of Loan* which contains a Customer and Book class. Kind of like this:

class Library
{
    vector<Loan*> loans_;
};

class Loan
{
    Customer *customer_;
    Book *book_;
};

I had a function which required going through all the initialized book objects and seeing which ones belonged to whom, like this:

Customer *getBorrower(Book *book)
{
    vector<Loan*>::iterator iter;

    for( iter = loans_.begin(); iter != loans_.end(); ++iter )
    {
        if( (*iter).getBook() == book )
            return (*iter).getCustomer();
        else
            continue;
    }
    return 0;
}

This stumped me, because in the Netbeans 6.9 IDE the (*iter). showed me a list of all the methods of the Loan object.

I was just about to quit the exam when I loaded up VC++08 and it asked me if I didn't want to use -> instead.

(*iter)->getBook(); worked to my chagrin.

So my question is: why did the IDE allow me to use . and even spit out a list of the methods as well as for ->? To my knowledge, it doesn't do this kind of madness anytime else. What exactly happened here? I'm not understanding what I tried to make the method do that gave me that weird netbeans error "Is not of type Loan*"

Second question: This is a style question. I commented to the professor about this, but he didn't seem too agreeable. The exam guidelines also had us create a public

vector<Book*> and vector<Customer*>.

We then accessed these from the main function to run our unit tests. I found this to be in extremely bad practise since a simple getter function would have provided us with what we needed without publicizing our information. Was I right to call this out as a bad design choice?

Error:

Library.cpp:14: error: request for member getCustomer' in(&iter)->__gnu_cxx::__normal_iterator<_Iterator, _Container>::operator* with _Iterator = Loan**, _Container = std::vector >', which is of non-class type `Loan*'

+2  A: 

The expression (*iter)->getBook() should work. The type vector<T>::iterator is something that "points to" an instance of T, and is usually a plain old T*. In your case, T is Loan*, so T* is Loan**. Thus iter is a Loan**, and so (*iter) is a Loan*, which you access using the -> operator.

Quite possibly NetBeans got as confused as you did, though it has less of an excuse. :-)

Marcelo Cantos
Clearly, `(*iter)->getBook()` is correct. I think the question is why NetBeans showed auto-completion for `(*iter).`, even though `(*iter)` is of type `Loan *`.
Matthew Flaschen
Exactly, Matthew pointed out the question, but thanks for the explanation! Always helps ^^
SoulBeaver
@Matthew: from the phrase, "worked to my chagrin," I got the impression that the OP thought the `->` syntax shouldn't work.
Marcelo Cantos
@Marcelo: Yes, to my dismay. It was an obscure error and I spent about an hour pestering the professors overlooking the exam about the error until I noticed the error. Shame they didn't see it either.
SoulBeaver
+1  A: 

In C, (*foo).bar will follow the foo pointer to the foo struct and find the bar member. Because this is a tedious amount of typing, foo->bar was introduced to follow the foo pointer to the foo struct and find the bar member.

So you have to choose your use of . vs -> based on whether you are working with a pointer to a structure or working with a structure.

Please note that I don't know how C++ has extended the use of -> and . with classes, but since the first C++ implementations were based on C with structs, I assume that -> and . work with classes the same way: objects of type class are dereferenced with . and objects of type pointer to class are dereferenced with ->. But that's conjecture on my part.

sarnold
I agree, but I don't understand why it allowed me to autocomplete with both `.` and `->` when I was actually working with the pointers which, as you correctly point out, need `->`
SoulBeaver
Most IDE environments differ from the compilers by a little too much... NetBeans probably did not follow your chain of templates and classes as well as Marcelo did.
sarnold
+2  A: 

Well, it seems that Intellisense is just better than NetBeans. ;)

(*iter)->getBook() is the right way to get to the method in this case. Notice that iterator is kind of pointer with overloaded operators * and -> to behave like ordinary pointer.

In your case, *iter is dereference of the element in vector, which is pointer. So, if you want to reach the method, you must use operator ->, so the construction (*iter)->getBook() is valid. As well as more obfuscated method: (*(*iter)).getBook().

Archie