|
|
c m s c 214
f a l l 2 0 0 1 |
vector<int>::iterator pos;The natural question to ask is: what is this crazy syntax for declaring an iterator?
Upon staring at the declaration more closely, you realize what kind of iterator pos is. It's an iterator for a vector of int values. Thus, this iterator can only be used to iterate on vector of int values. It can't be used to iterate on a vector of float values, or a vector of Foo values, or a vector of Foo pointers. Iterators are specific to a vector of a certain type.
Perhaps the crazy syntax was introduced when the STL was incorporated into Standard C++. After all, as long as namespaces and such are being added, why not change other things too? However, that's not a valid reason. A rule of thumb is not to create new syntax for a language unless there's some reasonable justification. In any case, STL existed and was implemented in C++ prior to being adopted into the Standard. So, it would suggest that this way of declaring iterators has been around for a while. And, so it has: it occurs with nested classes.
You can declare a nested class:
class Outer {
// PRIVATE nested class
class PrivateNested {
int data;
public:
PrivateNested & operator=( const PrivateNested & other );
};
public:
// PUBLIC nested class
class PublicNested {
int data;
};
};
Of course, you can declare data members, member functions, etc.
I haven't done so here.
For example, PrivateNested is a private nested class. Only Outer, PrivateNested and PublicNested can declare variables of type PrivateNested. If a method is not part of these classes, it can't declare a variable of type PrivateNested.
int main()
{
Outer::PublicNested foo;
}
Here's where you see the unusual syntax, using the doublye
colon. Since PublicNested is a nested class, then to
fully indicate the correct type, you must list the outer class
first, followed by two colon, then the nested (nested) class.
This allows other classes to have nested classes that are also called "PublicNested", without interfering with the "Outer::PublicNested" class. For example, there could be a "Foo::PublicNested" class. These would be two different classes.
In fact, you can have a class called PublicNested, which is not a nested class at all (despite it's name), and it will also not interfere with nested classes by the same name.
However, the compiler can't really determine a class is nested in the definition of the classes (which appears in the .cpp file) without special syntax. Alas, C++ has rather kludgy syntax for nested classes.
For example, here's how you would write the code for three
PrivateNested class methods: the default
constructor, some arbitrary function, and operator=.
// default constructor
Outer::PrivateNested::PrivateNested()
{
// code
}
// arbitrary function
void Outer::PrivateNested::foo()
{
// code
}
// operator=
Outer::PrivateNested &
Outer::PrivateNested::operator=( const Outer::PrivateNested &other )
{
// code
}
The operator= shows how vile the syntax can be. Whenever you want
to refer to PrivateNested, you must precede it by
Outer::. Why? Because there could be a non-nested
class called PrivateNested.
In an example like this, it doesn't seem possible that this could be the case. Who would ever call a non-nested class PrivateNested? While that's true, it's very possible for a nested class to be called Node. And it's very possible for a non-nested class to be called Node, too. The language needs special syntax to differentiate between the two cases. Thus, only the non-nested class is properly called "Node", while the nested Node would have to be preceded by the outer class's name and two colons.
Why didn't you have to use such kludgy syntax in the .h file? If you're declaring a nested class within a .h file, the language assumes you will be referring to the nested class. It's far more likely that you will refer to the name of the class in a declaration (i.e., in a class header), then to some other non-nested class by the same name. (There's probably some other syntax, like ::PrivateNested, if you really need to to refer to a non-nested class by the same name).
In C, this problem occurred all the time. You want to write a sort function on int arrays, float arrays, and Foo arrays. You'd have to name the functions different names in each case. In C++, functions can be overloaded, so it's no big deal. As long as two functions have different signatures (i.e., the number of parameters, the type of the parameters, and its constness), you can name them the same and the compiler can distinguish which is which.
The closest analogy is a nested class. Thus, having Node be a nested class of a singly linked list class, a doubly linked list class, and a binary search tree class ensures their names won't clash with one another.