Professional C__ - Marc Gregoire [149]
Demo d;
std::cout << pd->get() << std::endl; // prints 5
std::cout << d.get() << std::endl; // prints 5
std::cout << NS::get() << std::endl; // prints 20
std::cout << Demo::get() << std::endl; // prints 5
std::cout << ::get() << std::endl; // prints 10
std::cout << get() << std::endl; // prints 10
Code snippet from Scope\Scope.cpp
Note that if the namespace called NS is given as an unnamed namespace, then the following line will give an error about ambiguous name resolution, because you would have a get() defined in the global scope and another get() defined in the unnamed namespace.
std::cout << get() << std::endl;
This same error occurs if you add the following using clause right before the main() function:
using namespace NS;
C++11
C++11 has a lot of new functionality. This section describes a few new features that do not immediately fit elsewhere in this book.
Uniform Initialization
Before C++11, initialization of types was not always uniform. For example, take the following definition of a circle, once as a structure, once as a class:
struct CircleStruct
{
int x, y;
double radius;
};
class CircleClass
{
public:
CircleClass(int x, int y, double radius)
: mX(x), mY(y), mRadius(radius) {}
private:
int mX, mY;
double mRadius;
};
Code snippet from UniformInitialization\UniformInitialization.cpp
In pre-C++11, initialization of a variable of type CircleStruct and a variable of type CircleClass looks different:
CircleStruct myCircle1 = {10, 10, 2.5};
CircleClass myCircle2(10, 10, 2.5);
Code snippet from UniformInitialization\UniformInitialization.cpp
For the structure version you can use the {...} syntax. However, for the class version you need to call the constructor using function notation (...).
C++11 allows you to more uniformly use the {...} syntax to initialize types. Using that, you can rewrite the above as follows:
CircleStruct myCircle3 = {10, 10, 2.5};
CircleClass myCircle4 = {10, 10, 2.5};
Code snippet from UniformInitialization\UniformInitialization.cpp
The definition of myCircle4 will automatically call the constructor of CircleClass. The use of the equal sign is even optional, so the following is identical.
CircleStruct myCircle5{10, 10, 2.5};
CircleClass myCircle6{10, 10, 2.5};
Code snippet from UniformInitialization\UniformInitialization.cpp
Using this uniform initialization also prevents narrowing. C++ implicitly performs narrowing, for example:
void func(int i) { /* ... */ }
int main()
{
int x = 3.14;
func(3.14);
return 0;
}
C++ will automatically truncate 3.14 in both cases to 3 before assigning it to x or calling func(). Note that some compilers might issue a warning about this narrowing. This narrowing can be prevented by using uniform initialization:
void func(int i) { /* ... */ }
int main()
{
int x = {3.14}; // Error because narrowing
func({3.14}); // Error because narrowing
return 0;
}
Code snippet from UniformInitialization\UniformInitialization.cpp
Now both the assignment to x and the call to func() will generate a compiler error if your compiler fully conforms to the C++11 standard.
The same new uniform initialization can also be used on STL containers, which are discussed in depth in Chapter 12. For example, initializing a vector of strings used to require code as follows:
std::vector myVec.push_back("String 1"); myVec.push_back("String 2"); myVec.push_back("String 3"); With C++11 uniform initialization, this can be rewritten: std::vector Code snippet from UniformInitialization\UniformInitialization.cpp Uniform initialization can also be used to initialize dynamically allocated arrays. For example: int* pArray = new int[4]{0, 1, 2, 3}; Code snippet from UniformInitialization\UniformInitialization.cpp And last but not least, it can also be used in the constructor initializer to initialize arrays that are members of a class. class MyClass { public: MyClass() : mArray{0, 1, 2, 3} {} private: int mArray[4]; }; Code