Standard Library Math Functions
The function sqrt_sum needs to know what a Vector is and how to ask it for its size and its elements.
A Short File That Depends on Three Sources
Separate compilation divides code into files that are compiled independently, so user code can depend on an interface rather than an implementation. This article looks at the user side of that arrangement: a file that wants to use a class and some standard library functions, but does not contain the class's implementation. The example file is short, but it draws its names from three different places: a file written by someone else (Vector.h), a standard library header (cmath), and the std namespace that the standard library uses.
Before reading further, think about the file as a reader would. The function sqrt_sum needs to know what a Vector is and how to ask it for its size and its elements. It also calls sqrt. Which of the three include and using lines is responsible for each of those needs? And does the file need the code that implements Vector in order to be written and compiled, or does it only need something smaller? The rest of this article answers those questions by tracing the names in the file.
The Loop That Needs Names from Several Files
The body of sqrt_sum shows a standard library function used in ordinary code. The line sum += sqrt(v[i]); takes each element of the vector, computes its square root, and adds it to a running total. The source comment describes the loop as computing the sum of square roots. Written as a formula, the function returns the sum of the square roots of the elements, where $v_i$ stands for the element at index $i$ and $\sqrt{v_i}$ is its square root.
- The loop condition i !=
v.size()uses the interface of Vector. - v[i] uses the indexing operation of Vector.
- sqrt comes from the cmath header.
This fragment is an illustrative reconstruction of the lines the source quotes, not the full file. Notice that the function body combines three kinds of names: the size call and indexing operation belong to Vector, and sqrt belongs to the math library. Each one traces back to a specific line at the top of the file.
Interface Versus Implementation
The first line of user.cpp, #include "Vector.h", is the link between the user file and the class. The source comment explains its purpose: it gets Vector's interface. The interface is the part of the class that other code is allowed to see and use. It tells the compiler what a Vector is and what operations exist on it, such as the size() call and the indexing operation v[i]. The user file does not need to see how those operations are carried out.
The implementation lives in a separate file, Vector.cpp, which is compiled on its own. The user file is compiled separately as well. A linker then combines the compiled pieces into one working program. The compiler reads user.cpp and reads the interface in Vector.h; the linker is what joins the separately compiled Vector implementation to the user's code.
This is why the design is useful. The file that uses Vector can be written, read, and compiled on its own. Its author depends on what the interface promises, not on the details inside it. If the implementation changes but the interface stays the same, the user file does not need to be rewritten.
Headers That Bring Declarations Into Scope
A #include line copies the declarations from a header into the file that contains the line. The example uses two headers, and the Vector interface and the math library are included in different forms. The Vector interface is included as #include "Vector.h", with quotation marks. The math library is included as #include <cmath>, with angle brackets. The source does not explain the difference between these two forms, so this article only states what the example uses: Vector.h provides the Vector interface, and cmath provides the interface to the standard library math functions, including sqrt().
The include lines are therefore the first place to look when a name is unfamiliar. A name that comes from Vector.h is a member of the Vector interface, and a name that comes from cmath is a math library function. Neither include line by itself makes the names of the other file visible.
What the using Directive Changes
The line using namespace std; is a directive that makes the members of the std namespace visible in the file. The source comment states this purpose and points to a section of the text (§3.3) for more detail. Without this line, a standard library name such as sqrt would not be visible under its plain name. The same function can still be reached by writing the qualified name std::sqrt, which is the form that makes the namespace explicit at each use.
| Feature | #include <cmath> | using namespace std; |
|---|---|---|
| Main job | Brings in the declarations that define sqrt() | Makes std members visible without a prefix |
| Effect on sqrt | Makes sqrt declared in the file | Allows the plain name sqrt to be written |
| Without it | sqrt is not declared at all | sqrt must be written as std::sqrt |
| Kind of line | Copies declarations from a header | Name-visibility directive |
The include line and the namespace line do different jobs.
What do you think happens?
If the using namespace std; line were removed, would the plain call sqrt(v[i]) still be visible by that name?
Reveal answer
No. Without the using directive, sqrt is not visible under its plain name; the same function is still reachable as std::sqrt.
The cmath include still declares the function in the standard library's namespace. The using directive is only what allows the unqualified name to be written.
Tracing Where Each Name Is Introduced
When you trace user code, read it from the top and record the first line where each name becomes known. A name can be used only after the line that introduces it, so the top of the file tells you what the rest of the file is allowed to refer to.
Finding the Introducing Line for Each Name
In the user file, find the line that first introduces Vector, sqrt, the size call, and the indexing operation used inside sqrt_sum.
- 1Vector
The name Vector is introduced by #include "
Vector.h", which gives the compiler Vector's interface. - 2sqrt
The name sqrt is introduced by #include <cmath>, which provides the declaration of
sqrt(). - 3size() and v[i]
Both are operations of the Vector interface, so they are introduced by the same #include "
Vector.h" line that introduces Vector. - 4Plain sqrt
The plain spelling sqrt is usable without a prefix only because using namespace std; appears in the file. Without it, the code must use std::sqrt.
Vector, size(), and v[i] come from the Vector.h include. sqrt is declared by the cmath include and can be written plainly because of the using directive. Any later line in the function body can use these names because the introducing lines appear before it.
Mistakes When Reading Include and Using Lines
Common mistake Assuming the using directive is what makes sqrt available at all
Why it failsThe cmath include declares sqrt. The using directive only controls whether the name can be written without the std prefix.
Do this insteadCheck the cmath include for the declaration, and check the using line only for the plain-name spelling.
Common mistake Thinking Vector.h contains the whole class implementation
Why it failsThe source describes
Vector.has providing the interface, the part other code is allowed to see. The implementation lives inVector.cpp.Do this insteadTreat Vector.h as the description of what Vector offers, and Vector.cpp as the file that carries out those operations.
Common mistake Treating the two include forms as interchangeable without checking
Why it failsThe example uses quotation marks for
Vector.hand angle brackets for cmath. The source does not explain the difference, so the form should be copied as written rather than guessed.Do this insteadUse #include "Vector.h" and #include <cmath> exactly as the example does.
Common mistake Expecting a name to work on a line above the line that introduces it
Checking Your Reading of the File
Using only the include and using lines of the user file, explain which line makes the name Vector usable, which line makes the plain name sqrt usable, and what the function body needs from each of them. Then say which of these two lines you would need to change if you wanted to write std::sqrt at the call site instead.
Hints
- Start with the #include line that gives the Vector interface.
- Remember that the cmath include declares sqrt and the using line controls the plain spelling.
- Changing the call to std::sqrt removes the need for the using line for that call.
Key Takeaways
- User code can depend on a class it did not implement by including the class's interface file, such as
Vector.h, which exposes what other code is allowed to see and use. - The #include <cmath> line provides the declarations for standard math functions such as
sqrt(), while #include "Vector.h" supplies the Vector interface. - The using namespace std; directive makes std members visible under plain names; without it, the qualified name std::sqrt is still available.
- To trace a name, read the file from the top and find the first line that introduces it, because a name can only be used after that line.