Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Professional C++ [eng].pdf
Скачиваний:
284
Добавлен:
16.08.2013
Размер:
11.09 Mб
Скачать

Understanding C++ Quirks and Oddities

Scope Resolution

As a C++ programmer, you need to familiarize yourself with the concept of scope. Every name in your program, including variable, function, and class names, is in a certain scope. You create scopes with namespaces, function definitions, and class definitions. When you try to access a variable, function, or class, the name is first looked up in the nearest enclosing scope, then the next scope, and so forth, up to the global scope. Any name not in a namespace, function, or class is in the global scope.

Sometimes names in scopes hide identical names in other scopes. Other times, the scope you want is not part of the default scope resolution from that particular line in the program. If you don’t want the default scope resolution for a name, you can qualify the name with a specific scope using the scope resolution operator ::. For example, to access a static method of a class, you prefix the method name with the name of the class (its scope) and the scope resolution operator:

class Demo

{

public:

static void method() {}

};

int main(int argc, char** argv)

{

Demo::method();

return (0);

}

There are other examples of scope resolution throughout this book. One point, however, deserves further attention: accessing the global scope. The global scope is unnamed, so there’s no way to access it specifically. Instead, you can use the scope resolution operator by itself (with no name prefix): this always refers to the global scope. Here is an example:

int name = 3;

int main(int argc, char** argv)

{

int name = 4;

cout << name << endl; // Accesses local name cout << ::name << endl; // Accesses global name

return (0);

}

Header Files

Header files are a mechanism for providing an abstract interface to a subsystem or piece of code. One of the trickier parts of using headers is avoiding circular references and multiple includes of the same header file. For example, perhaps you are responsible for writing the Logger class that performs all

343

Chapter 12

error message logging tasks. You may end up using another class, Preferences, that keeps track of user settings. The Preferences class may in turn use the Logger class indirectly, through yet another header.

As the following code shows, the #ifndef mechanism can be used to avoid circular and multiple includes. At the beginning of each header file, the #ifndef directive checks to see if a certain key has not been defined. If the key has been defined, the compiler will skip to the matching #endif, which is usually placed at the end of the file If the key has not been defined, the file will proceed to define the key so that a subsequent include of the same file will be skipped.

// Logger.h

#ifndef __LOGGER__

#define __LOGGER__

#include “Preferences.h”

class Logger

{

public:

static void setPreferences(const Preferences& inPrefs); static void logError(const char* inError);

};

#endif // __LOGGER__

Another tool for avoiding problems with headers is forward references. If you need to refer to a class but you cannot include its header file (for example, because it relies heavily on the class you are writing), you can tell the compiler that such a class exists without providing a formal definition through the #include mechanism. Of course, you cannot actually use the class in the code because the compiler knows nothing about it, except that the named class will exist after everything is linked togther However, you can still make use of pointers or references to the class in your class definition. In the following code, the Logger class refers to the Preferences class without including its header file.

// Logger.h

#ifndef __LOGGER__ #define __LOGGER__

class Preferences;

class Logger

{

public:

static void setPreferences(const Preferences& inPrefs); static void logError(const char* inError);

};

#endif // __LOGGER__

344