Session recap
Functional programming paradigm exits for several decades but only entered the industry when Erlang was used for the Ericsson phones, somewhere in the late 1980s (arguably there can be found some Lisp commercial products )
There are many functional languages, the most clean and less likely to be used in the industry (but is considered the flagship of FP is
Haskell but there are many others such as MS F# , OCamel, ML etc, of which some are becoming really popular because they run on the Java Virtual Machine such as Scala, Scheme and Clojure.
Functional programming adheres to Lambda Calculus, a formal system to express computation
Of course many other multi-paradigm languages support FP (either partially or fully), such as Python, Ruby, Perl and even C++.
If I understood correctly you wanted to know what the reinterpret_cast is for.
We called std::istream method read which has the following signature
istream& read (char* s, streamsize n);
Notice that the first argument requires a char* (a Pointer to array of characters) and we had a pointer to unsigned short, we needed to cast it from pointer to unsigned short to pointer to character.
In C we have only one type of casting operator, marked in green
int a = 1;
double d = (double)a;
int *pI = &a;
double *pD = (double*)pI;
C Cast is still supported in c++ but In C++ there are additional 4 different cast operators
Why?
The 4 C++ casts are
See more next pages
int i = 7;
double d = static_cast<double>(i); // Compiler will change the bit representation
class Base {}
class Derived : public Base {}
Derived d;
Base b = static_cast<Base>(d); // Up cast
Base* pB = new Derived();
Derived* pD = static_cast<Derived*>(pB); // May be risky if pB is not Derived
std::string s = static_cast<string>("Some text"); // Compiler will actually call constructor
Static cast may generate some code, it is mostly safe except when a Base class pointer is cast to a derived class pointer.
Down cast is not allowed in virtual base classes
Used for down casting a reference or a pointer to a more specific type in the class hierarchy. Type safety check is performed on runtime and if the types are incompatible an exception is thrown. Require Runtime Type Information (RTTI)
class Base {};
class DerivedLeft : virtual Base {};
class DerivedRight : virtual Base {};
class Derived : public DerivedLeft, public DerivedRight;
Base* pB = new Derivde();
DerivedLeft* pDL = dynamic_cast<DerivedLeft*>(pB);
C cast operator can easily remove const-ness even when we don't intend to
void foo(const unsigned short* buffer)
{
char* pC = (char*)buffer; // The const was removed
....
}
But, const is usually there for a reason and removing it is usually due to social circumstances and not the regular modus operadi, thus, other cast operator are not allowed to remove const-ness and this new cast was introduced
void foo(const unsigned short* buffer)
{
char* pC = const_cast<char*>(buffer); // Performed explicitly. So probably that's what we want
....
}
Sometimes we are required to use a reference or a pointer of a specific type while we have another type altogether, just like in our ifstream::read that expects a char* while we have unsigned short*.
reinterpret_cast, tells the compiler to ignore the type system and just consider the pointer(or reference) to be of a different type.
This may is a risky cast, it subvert the type system and the responsibility for correctness lies on the programmer.
int* pI= new int[10];
double* pD = reinterpret_cast<double*>(pI);
The above example, while syntactically correct, is very likely a bug.
I wanted to mention that if we would like to access the 3D matrix using its coordinates instead of repeating the formula we can implement
template <class T>
class Matrix {
...
T& operator(size_t h, size_t w, size_t d) const { ... };
};
Martix<unsigned short> m(HEIGHT, WIDTH, DEPTH);
cout << m(10, 11, 12) << endl; // Display element at (10, 11, 12)
m(10, 11, 12) = 100; // Assign that element a different value.
As we already mentioned that, I will commit it to a slide
How to read entire file to a vector?
#include <vector>
#include <iterator> // for input_iterator and output_iterator
fstream file("FileName", fstream::in | fstream::binary); // Flags may differ
vector<unsigned short> vec(istream_iteator<unsigned short>(file), istream_iterator<unsigned short>());
file.close();
The above will read into vec the entire file. However, vec is a new declared vector, what if we already have an empty vector?
#include <vector>
#include <algorithm> // For copy
#include <iterator> // for input_iterator and output_iterator
vector<unsigned short> vec;
fstream file("FileName", fstream::in | fstream::binary); // Flags may differ
copy(istream_iteator<unsigned short>(file), istream_iterator<unsigned short>(), back_inserter(vec));
file.close();
We probably need to clarify that in next session.
So we can read a file to a vector, what about write a vector to a file?
#include <iterator> // For output_iterator
#include <algorithm> // For copy
fstream file("filename", ios::out | ios::binary);
copy(vec.begin(), vec.end(), ostream_iterator<unsigned short>(file));
file.close();