No, #include
still works exactly the same in C++.
To understand using
, you first need to understand namespaces. These are a way of avoiding the symbol conflicts which happen in large C projects, where it becomes hard to guarantee, for example, that two third-party libraries don't define functions with the same name. In principle everyone can choose a unique prefix, but I've encountered genuine problems with non-static C linker symbols in real projects (I'm looking at you, Oracle).
So, namespace
allows you to group things, including whole libraries, including the standard library. It both avoids linker conflicts, and avoids ambiguity about which version of a function you're getting.
For example, let's create a geometry library:
// geo.hpp
struct vector;
struct matrix;
int transform(matrix const &m, vector &v); // v -> m . v
and use some STL headers too:
// vector
template <typename T, typename Alloc = std::allocator<T>> vector;
// algorithm
template <typename Input, typename Output, typename Unary>
void transform(Input, Input, Output, Unary);
But now, if we use all three headers in the same program, we have two types called vector
, two functions called transform
(ok, one function and a function template), and it's hard to be sure the compiler gets the right one each time. Further, it's hard to tell the compiler which we want if it can't guess.
So, we fix all our headers to put their symbols in namespaces:
// geo.hpp
namespace geo {
struct vector;
struct matrix;
int transform(matrix const &m, vector &v); // v -> m . v
}
and use some STL headers too:
// vector
namespace std {
template <typename T, typename Alloc = std::allocator<T>> vector;
}
// algorithm
namespace std {
template <typename Input, typename Output, typename Unary>
void transform(Input, Input, Output, Unary);
}
and our program can distinguish them easily:
#include "geo.hpp"
#include <algorithm>
#include <vector>
geo::vector origin = {0,0,0};
typedef std::vector<geo::vector> path;
void transform_path(geo::matrix const &m, path &p) {
std::transform(p.begin(), p.end(), p.begin(),
[&m](geo::vector &v) -> void { geo::transform(m,v); }
);
}
Now that you understand namespaces, you can also see that names can get pretty long. So, to save typing out the fully-qualified name everywhere, the using
directive allows you to inject individual names, or a whole namespace, into the current scope.
For example, we could replace the lambda expression in transform_path
like so:
#include <functional>
void transform_path(geo::matrix const &m, path &p) {
using std::transform; // one function
using namespace std::placeholders; // an entire (nested) namespace
transform(p.begin(), p.end(), p.begin(),
std::bind(geo::transform, m, _1));
// this ^ came from the
// placeholders namespace
// ^ note we don't have to qualify std::transform any more
}
and that only affects those symbols inside the scope of that function. If another function chooses to inject the geo::transform
instead, we don't get the conflict back.