vector<int> Inheritance Notes¶
inheritance is a way of creating a new class from an existing class
for example, consider the standard vector<int>
it already exists, and we can use it to do things like this:
vector<int> v;
v.push_back(4);
v.push_back(5);
v.push_back(1);
for(int i = 0; i < v.size; i++) {
cout << v[i] << "\n";
}
now suppose we want a new class that is just like vector<int>, but the
vector has a name, e.g. we want to be able to do things like this:
int_vec v("Table 2.1");
v.push_back(4);
v.push_back(5);
v.push_back(1);
v.sort();
cout << v.get_name() << "\n";
for(int i = 0; i < v.size; i++) {
cout << v[i] << "\n";
}
cout << "sum = " << v.sum() << "\n";
this int_vec does everything a vector<int> does, except it also has
- a constructor and getter for its name
- methods
sortandsum(that do what they say)
to create int_vec, we will use inheritance
this means we will inherit all the functionality of vector<int> into
int_vec, and then add extra member variables and methods
we can start like this:
#include <iostream>
#include <vector>
using namespace std;
class int_vec : public vector<int> {
// nothing yet!
}; // class int_vec
int main() {
int_vec v;
v.push_back(4);
v.push_back(5);
v.push_back(1);
for(int n : v) cout << n << "\n";
}
the line class int_vec : public vector<int> uses inheritance to define a
new class named int_vec that has all the functionality of vector<int>
this by itself is no great thing: practically int_vec is just another name
for vector<int>
A Note on public Inheritance¶
note that we write : public vector<int>
- the
publicqualifier here means that anypublicmember variables or methods invector<int>remainpublic, and similarlyprivatemember variables remainprivate - C++ also allows : protected vector<int>`, which inherits all member
variables or methods in
vector<int>so that they areprotectedinint_vec; while we’re not usingprotectedmuch, if at all, in this course, aprotectedmember is essentially one that is accessible in a class, or in any class that inherits from it - C++ also allows : private vector<int>` inheritance, which inherits all
member variables or methods in
vector<int>so that they areprivateinint_vec
in this course, inheritance will always mean public-style inheritance,
e.g. : public vector<int>
public-style inheritance means that the access level of the member
variables and methods in the class being inherited from don’t change
Adding Some Helper Functions¶
something that is easy to do is to add helper functions, e.g.:
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
using namespace std;
class int_vec : public vector<int> {
public:
int sum() const {
return accumulate(begin(), end(), 0);
}
}; // class int_vec
int main() {
int_vec v;
v.push_back(4);
v.push_back(5);
v.push_back(1);
for(int n : v) cout << n << "\n";
cout << "sum = " << v.sum() << "\n";
}
sum returns the sum of all the elements in the int_vec
begin() and end() are methods defined in vector<int> that return
iterators
iterators are a generalization of pointers
begin()returns an iterator to the first element of theint_vecend()returns an iterator to one past the last element of theint_vecaccumulate(begin() end(), 0)is thus the sum of all the elements in theint_vecyou could also use a loop instead:
int sum() const { int result = 0 for(int n : *this) result += n; return result; }
here’s another example where we add a helper method for sorting:
// ...
#include <algorithm>
using namespace std;
class int_vec : public vector<int> {
public:
// ...
void sort() {
std::sort(begin(), end());
}
}; // class int_vec
int main() {
int_vec v;
v.push_back(4);
v.push_back(5);
v.push_back(1);
v.sort();
for(int n : v) cout << n << "\n";
cout << "sum = " << v.sum() << "\n";
}
the sort() method is not const because it may actually modify the
underlying numbers
- also note that we must write
std::sortin the body to avoid recursively calling thesort()method
Adding a Name¶
now lets add a string for the name of the int_vec:
// ...
#include <string>
// ...
class int_vec : public vector<int> {
string name;
public:
int_vec(const string& s)
: vector<int>(), // call default constructor of vector<int>
name(s)
{ }
string get_name() const {
return name;
}
// ...
}; // class int_vec
first, notice how the constructor calls the vector<int>() default
constructor
this is important!: we must call a vector<int> to ensure that it is
initialized properly
after the vector<int> constructor finishes, we then construct the things
specific to int_vec, i.e. we initialize name
second, we add a getter called get_name that returns the name of the
int_vec
- we might also add a
set_name(string)method to set the name, but for this class we’ve decided that you can’t change a name once you’ve set it
An int_vec is a vector<int>¶
an important idea here is that int_vec extends the functionality of
vector<int> by adding new methods and member variables
an int_vec can do everything a vector<int> does, and more
for example, suppose we write a function called summarize:
// ...
void summarize(const vector<int>& v) {
for(int i = 0; i < v.size(); i++) {
cout << "v[" << i << "] = " << v[i] << "\n";
}
cout << "size : " << v.size() << "\n";
}
int main() {
int_vec v("Table 1");
v.push_back(4);
v.push_back(5);
v.push_back(1);
v.sort();
summarize(v);
}
summarize takes a vector<int> as input, but we pass it an int_vec
in the code above
that’s okay, because an int_vec can do everything a vector<int> does
(and more)
but now suppose we add the function fancy_summarize:
void summarize(const vector<int>& v) {
for(int i = 0; i < v.size(); i++) {
cout << "v[" << i << "] = " << v[i] << "\n";
}
cout << "size: " << v.size() << "\n";
}
void fancy_summarize(const int_vec& v) {
cout << v.get_name() << ":\n";
for(int n : v) cout << " " << n << "\n";
cout << "sum = " << v.sum() << "\n";
}
int main() {
int_vec v("Table 1");
v.push_back(4);
v.push_back(5);
v.push_back(1);
v.sort();
summarize(v);
cout << "\n";
fancy_summarize(v);
}
fancy_summarize takes an int_vec as input, and so we can pass v to
it
however, this code does not work with fancy_summarize:
int main() {
vector<int> w;
fancy_summarize(w); // error: doesn't compile
}
this causes a compiler error because you cannot pass a vector<int> to a
function that needs an int__vec
it is clear why this can’t work: inside of fancy_summarize,
v.get_name() and v.sum() are called, but a vector<int> does not
have a get_name or sum method
Constructor: Reading Numbers from a File¶
most of our constructors have been very simple — often empty!
so here is an int_vec constructor that opens a file of numbers and reads
them in:
// ...
#include <fstream>
using namespace std;
class int_vec : public vector<int> {
// ...
public:
int_vec(const string& s)
: vector<int>(), // call default constructor of vector<int>
name(s)
{ }
int_vec(const string& s, const string& fname)
: vector<int>(), name(s)
{
ifstream infile(fname);
if (infile.fail()) {
cmpt::error("int_vec: cannot open file");
}
int num = 0;
while (infile >> num) {
push_back(num);
}
}
// ...
};
int main() {
int_vec v("Table 2", "nums.txt");
fancy_summarize(v);
}
note that if fname cannot be read, then infile.fail() will be true,
and so we throw an error
this is important: this particular constructor does not let us create an
int_vec if fname cannot be properly read
however, if fname is the name of a file that contains some non-integer
values, then the constructor will usually stop reading the file as soon as it
encounters the first non-integer
- this might not be the best behavior
- it might be better to throw an exception if a non-integer is encountered
one other annoyance here is that this constructor requires two strings, and its up to the programmer to remember the name of the vector comes before the name of the file