You are on page 1of 4

Now callers who want a specific version can call the fully qualified names, for

example,
callers could use utilities::V2::poll_data to use the newer version and
utilities::poll_data to use the older version. When an item in a specific namespace
calls an item in the same namespace, it does not have to use a qualified name. So,
if the
new_feature function calls get_data, it will be utilities::V2::get_data that is
called. It is important to note that, to declare a nested namespace, you have to do
the
nesting manually (as shown here); you cannot simply declare a namespace called
utilities::V2.
Understanding Language Features
[ 63 ]
The preceding example has been written so that the first version of the code will
call it using
the namespace utilities. C++11 provides a facility called an inline namespace that
allows
you to define a nested namespace, but allows the compiler to treat the items as
being in the
parent namespace when it performs an argument-dependent lookup:
namespace utilities
{
inline namespace V1
{
bool poll_data();
int get_data();
}
namespace V2
{
bool poll_data();
int get_data();
int new_feature();
}
}
Now to call the first version of get_data, you can use utilities::get_data or
utilities::V1::get_data.
Fully qualified names can make the code difficult to read, especially if your code
will only
use one namespace. To help here you have several options. You can place a using
statement to indicate that symbols declared in the specified namespace can be used
without
a fully qualified name:
using namespace utilities;
int i = get_data();
int j = V2::get_data();
You can still use fully qualified names, but this statement allows you to ease the
requirement. Note that a nested namespace is a member of a namespace, so the
preceding
using statement means that you can call the second version of get_data with either
utilities::V2::get_data or V2::get_data. If you use the unqualified name, then it
means that you will call utilities::get_data.
A namespace can contain many items, and you may decide that you only want to relax
the
use of fully qualified names with just a few of them. To do this, use using and
give the
name of the item:
using std::cout;
using std::endl;
cout << "Hello, World!" << endl;
Understanding Language Features
[ 64 ]
This code says that, whenever cout is used, it refers to std::cout. You can use
using
within a function, or you can put it as file scope and make the intention global to
the file.
You do not have to declare a namespace in one place, you can declare it over
several files.
The following could be in a different file to the previous declaration of
utilities:
namespace utilities
{
namespace V2
{
void print_data();
}
}
The print_data function is still part of the utilities::V2 namespace.
You can also put an #include in a namespace, in which case the items declared in
the
header file will now be part of the namespace. The standard library header files
that have a
prefix of c (for example, cmath, cstdlib, and ctime) give access to the C runtime
functions by including the appropriate C header in the std namespace.
The great advantage of a namespace is to be able to define your items with names
that may
be common, but are hidden from other code that does not know the namespace name of.
The namespace means that the items are still available to your code via the fully
qualified
name. However, this only works if you use a unique namespace name, and the
likelihood is
that, the longer the namespace name, the more unique it is likely to be. Java
developers
often name their classes using a URI, and you could decide to do the same thing:
namespace com_packtpub_richard_grimes
{
int get_data();
}
The problem is that the fully qualified name becomes quite long:
int i = com_packtpub_richard_grimes::get_data();
You can get around this issue using an alias:
namespace packtRG = com_packtpub_richard_grimes;
int i = packtRG::get_data();
Understanding Language Features
[ 65 ]
C++ allows you to define a namespace without a name, an anonymous namespace. As
mentioned previously, namespaces allow you to prevent name clashes between code
defined in several files. If you intend to use such a name in only one file you
could define a
unique namespace name. However, this could get tedious if you had to do it for
several
files. A namespace without a name has the special meaning that it has internal
linkage, that
is, the items can only be used in the current translation unit, the current file,
and not in any
other file.
Code that is not declared in a namespace will be a member of the global namespace.
You
can call the code without a namespace name, but you may want to explicitly indicate
that
the item is in the global namespace using the scope resolution operator without a
namespace name:
int version = 42;
void print_version()
{
std::cout << "Version = " << ::version << std::endl;
}
C++ scoping of variables
As you saw in the previous chapter the compiler will compile your source files as
individual items called translation units. The compiler will determine the objects
and
variables you declare and the types and functions you define, and once declared you
can
use any of these in the subsequent code within the scope of the declaration. At its
very
broadest, you can declare an item at the global scope by declaring it in a header
file that will
be used by all of the source files in your project. If you do not use a namespace
it is often
wise when you use such global variables to name them as being part of the global
namespace:
// in version.h
extern int version;
// in version.cpp
#include "version.h"
version = 17;
// print.cpp
#include "version.h"
void print_version()
{
std::cout << "Version = " << ::version << std::endl;
}
Understanding Language Features
[ 66 ]
This code has the C++ for two source files (version.cpp and print.cpp) and a header
file
(version.h) included by both source files. The header file declares the global
variable
version, which can be used by both source files; it declares the variable, but does
not
define it. The actual variable is defined and initialized in version.cpp; it is
here that the
compiler will allocate memory for the variable. The extern keyword used on the
declaration in the header indicates to the compiler that version has external
linkage, that
is, the name is visible in files other than where the variable is defined. The
version variable
is used in the print.cpp source file. In this file, the scope resolution operator
(::) is used
without a namespace name and hence indicates that the variable version is in the
global
namespace.
You can also declare items that will only be used within the current translation
unit, by
declaring them within the source file before they are used (usually at the top of
the file).
This produces a level of modularity and allows you to hide implementation details
from
code in other source files. For example:
// in print.h
void usage();
// print.cpp
#include "version.h"
std::string app_name = "My Utility";
void print_version()
{
std::cout << "Version = " << ::version << std::endl;
}
void usage()
{
std::cout << app_name << " ";
print_version();
}
The print.h header contains the interface for the code in the file print.cpp. Only
those
functions declared in the header will be callable by other source files. The caller
does not
need to know about the implementation of the usage function, and as you can see
here it is
implemented using a call to a function called print_version that is only available
to code
in print.cpp. The variable app_name is declared at file scope, so it will only be
accessible
to code in print.cpp.
If another source file declares a variable at file scope, that is called app_name,
and is also a
std::string the file will compile, but the linker will complain when it tries to
link the
object files. The reason is that the linker will see the same variable defined in
two places and
it will not know which one to use.
Understanding Language Features
[ 67 ]
A function also defines a scope; variables defined within the function can only be
accessed
through that name. The parameters of the function are also included as variables
within the
function, so when you declare other variables, you have to use different names. If
a
parameter is not marked as const then you can alter the value of the parameter in
your
function.
You can declare variables anywhere within a function as long

You might also like