class MStd
{
public:
/**
* Opens file fname for input reads all the integers and returns
* them in a vector.
* @param fname - the input file name
* @return - vector containing all integers in the input file.
* If the file cannot be opened the returned vector
* has size 0.
*/
static vector<int> readInts(const string& fname);
/**
* Linear search of the vector v for integer x.
* @param x - integer to search for in v
* @param v - vector of integers to search for x
* @return - the first index i such that v[i] == x
* or -1 if x is not in v.
*/
static int lrank(int x, vector<int>& v);
/**
* Finds the substrings of s separated by 1 or more characters in
* the delim string. These substrings are returned in a vector.
* @param s - the string to split
* @param delim - a string of characters treated as separators
* between the substrings to be returned.
* @return - a vector consisting of the substrings found
*/
static vector<string> split(const string& s, const string& delims);
};
What is the syntax for definining a subclass B of a class A?
C++ has class types and also pointer to class types. I'll refer to the
first as a value type and the second as a reference type.
Which of these types is polymorphic and which is
monomorphic?
A variable declared as a monomorphic types may only hold different
values during execution, but they must all be of one type specified by
the declaration.
A variable declared as polymorphic type may not only hold different
values during execution, but these may even be of different types.
A variable of type pointer to A, where A is a class is potentially a
polymorphic type. During execution such a variable can hold values
which are of type pointer to A or of type pointer to any class
descended from A.
A function f declared to be virtual in a base class A
can optionally be given a new implementation in a derived class B.
To give a new implementation, the function f should be declared again
in B. In this case it should have the exact same signature.
Replacement means B::f is given an new implementation
that does not repeat or invoke A::f that whose implementation
it is "replacing".
Alternatively, refinement would mean that B::f does the
same thing as A::f but also adds some additional action
(presumably involving data members in B that are not in A).
Constructors for classes typically use refinement. Indeed if no
A constructor is invoked explicitly by a B constructor,
the compiler will invoke an available no argument A constructor.
What is a constructor initialization list, where does it appear
sytactically and when does it execute compared to the body of the
constructor?
If a function g in a class A is not virtual, can a function g
of the same signature be defined in a subclass B?
class A
{
public:
...
void g(int x);
...
};
class B : public A
{
public:
...
void g(int x);
...
};
int main()
{
A *pa = new B();
pa->g(); // Does this use dynamic dispatch to determine which g?
}
Shape * shapes[100];
int N; // number of Shapes in shapes array
void handler(Point p)
{
Shape *sp;
for(int i = 0; i < N; i++) {
sp = shapes[i];
if ( sp is pointing to a Rectangle that contains p) {
sp->drawRectangle();
} else if ( sp is pointing to a Circle that contains p){
sp->drawCircle();
} ... etc.
}
void handler(Point p)
{
Shape *sp;
for(int i = 0; i < N; i++) {
sp = shapes[i];
if ( sp->contains(p) ) {
sp->draw();
}
}
}
Since C++ allows variables declared to hold either class values or
pointers (references) to class values, one has write classes to be
prepared to handle the situations where C++ automatically makes copies
of class values and automatically destroys class values:
assignment
passing parameters by value
a local class value (created on the call) goes out of scope
You may need to define:
a. Copy constructor Used for passing class objects by value
b. operator= (assignment operator)
c. destructor
When do you need to use the "rule of 3" and define these members?
Typically when the class has pointer members which the class itself
has allocated the storage on the heap using new and is responsible for
this extra storage. The extra part on the heap is not automatically
copied by the default copy constructor, default
assignment operator. The extra storage on the heap is also not
automatically deleted when the object containing the pointer member is
deallocated.
Templates provide a different kind of reuse than that provided by
inheritance with dynamic dispatch. Templates are also extensively used
for the C++ Standard Template Library which implements a large number
of data structures and also algorithms.
The algorithms in STL are implemented as template functions -
typically non-member functions.
The data structures in STL are implemented as template classes.
In C++ iterators are modeled after pointers into arrays. That
is, pointers to arrays satisfy the properties of iterators and
iterators generalize these properties to other data structures such as
lists, dictionaries, etc.
vector<string> v; // empty vector of strings
vector<bool> w(10, false); // vector with 10 elements with
// each element set to false
int a[] = {1,2,3,5,8,13,21,34}; // int array with 8 elements
vector z(a, a + 8); // vector initialized with
// the 8 elements from a.
vector::iterator startz = z.begin();
vector::iterator limitz = z.end();
vector::iterator i;
bool found = false;
int x;
cin >> x;
for(i = startz; i != limitz; ++i) {
if ( *i == x ) {
found = true;
break;
}
}
template <class Iterator, class T>
bool find(Iterator start, Iterator limit, const T& x)
{
for(Iterator p = start; p != limit; p++) {
if ( *p == x ) {
return true;
}
}
return false;
}
int main()
{
int a[] = {1,2,3,5,8,13,21,34}; // int array with 8 elements
vector z(a, a + 8); // vector initialized with
// the 8 elements from a.
vector::iterator startz = z.begin();
vector::iterator limitz = z.end();
bool ba, bz;
ba = find(a, a + 8, 21); // ba will be set to true
bz = find(start, limitz, 21) // bz will also be set to true
It has a size() method (how much used storage) and capacity()
(how much available storage). The push_back method checks and doubles
the size if size is equal to capacity. So vectors grow automatically.
We will follow a systematic study of vector next time (chapter 5).
STL also has many template functions which implement traditional and
useful algorithms. These template functions are reusable since the
type of the elements they can be applied to is parametrized and can be
specified simply by passing a given type to the function.
For example, STL has a sort function:
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
vector<string> v;
// Store values in v
...
// Now sort strings in v in usual order
sort(v.begin(), v.end());
...
}
The same sort statement works with no change if v is a vector of
some other type such as int.