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 ab开发者_如何学编程out 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*'
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. :-)
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()
.
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.
精彩评论