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
sort
andsum
(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
public
qualifier here means that anypublic
member variables or methods invector<int>
remainpublic
, and similarlyprivate
member variables remainprivate
- C++ also allows : protected vector<int>`, which inherits all member
variables or methods in
vector<int>
so that they areprotected
inint_vec
; while we’re not usingprotected
much, if at all, in this course, aprotected
member 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 areprivate
inint_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_vec
end()
returns an iterator to one past the last element of theint_vec
accumulate(begin() end(), 0)
is thus the sum of all the elements in theint_vec
you 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::sort
in 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