C++ classes are similar to Java classes in many ways, but there are also important differences. Below is an example of a C++ class named IntList to be used to represent a list of integers; operations to add a value to the end of the list and to print the list are provided. The implementation uses a dynamically allocated array to store the integers; when the array is full, a new array of twice the size is allocated.
In Java, the class definition would all be in a single file. However, in C++ the code that defines the class would be split into two files: the first part specifies what member functions (methods) and data members (fields) the class will have. That code goes into a header file: a file with the extension .h. It is usually a good idea (though not a requirement as in Java) to give the file the same name as the class (so the file would be named IntList.h).
The second part of the class definition gives the code for the function bodies. That code goes in a source file (e.g., IntList.C).
The reason for splitting up the code is that it is generally a good idea to try to separate the interface from the implementation. Someone who wants to use an IntList really only needs to know what IntList operations are available; it is not necessary to know all the details about how an IntList is implemented. However, splitting up the code in this way is not required by C++. Some people prefer to include code for the member functions in the .h file when that code involves only one or two statements.
Here is the code that would be in IntList.h:
#include <iostream> class IntList { public: IntList(); // constructor; initialize the list to be empty void AddToEnd(int k); // add k to the end of the list void Print(ostream &output) const; // print the list to output private: static const int SIZE = 10; // initial size of the array int *Items; // Items will point to the dynamically allocated array int numItems; // number of items currently in the list int arraySize; // the current size of the array };Things to note about the example so far:
void f(const IntList &L) { L.Print(cout); }
#include "IntList.h" IntList::IntList(): Items(new int[SIZE]), numItems(0), arraySize(SIZE) { } void IntList::AddToEnd(int k) { ... } void IntList::Print(ostream &output) const { ... }Things to note about this part of the example:
IntList::IntList() { Items = new int[SIZE]; numItems = 0; arraySize = SIZE; }
The main reason to use a member initialization list is when a data member is itself a class object, and you don't want the default initialization of that object. If you initialize the data member inside the body of the constructor function it will already have been initialized using its default (no-arg) constructor, which is a waste of time.
As in Java, constructor functions can be overloaded (there can be
multiple constructors for a class, as long as each has a different number
and/or type of parameters).
In C++, a constructor function is called either when a class object is
declared:
To use a constructor with parameters, just put the values for the parameters
in parentheses as follows:
More detailed documentation on strings is available:
click here.
To use the vector class you must #include <vector>.
A vector is similar to an array, but vectors provide some operations that
cannot be performed using C++ arrays, and vectors can be passed both by value
and by reference (unlike C++ arrays, which are always passed by reference).
Unfortunately, there is no bounds checking for vectors (i.e., an index out
of bounds does not necessarily cause a runtime error).
Test your function with the following main function:
Question 1:
To extend the IntList class to include member function
Length, the following would be added to the public part of the
class declaration (in the file IntList.h):
The code for the Length function (to be added to the file
IntList.C) is:
Question 2:
To extend the IntList class by adding a 2-argument constructor,
the following would be added to the public part of the class declaration:
Constructor Functions
IntList L; // L's no-arg constructor function is called
or when the object is dynamically allocated:
IntList *p; // no constructor called yet
p = new IntList; // now the no-arg constructor is called
IntList L(1, 10); // L's 2-arg constructor will be called
IntList *p;
p = new IntList(0, 5, 22); // L's 3-arg constructor will be called
Two Useful Standard Classes: string and vector
The string class
To use the string class you must #include <string> (be sure
that you do not include string.h, because then you will get the
header file for C-style strings rather than for the C++ string class).
string s1; // s1 is initialized to the empty string
string s2("hello"); // s2 is initialized to the string "hello"
string s3 = "goodbye"; // s3 is initialized to the string "goodbye"
string s1, s2 = "hello";
cout << s1.size(); // s1's size is 0
cout << s2.size(); // s2's size is 5
string s1("abc");
string s2;
s2 = "abc";
if (s1 == s2) ... // yes! the two strings ARE equal
string s1("hello");
string s2("goodbye");
string s3 = s1 + " and " + s2; // the value of s3 is "hello and goodbye"
string s1 = "hello";
for (int k=s1.size()-1; k>=0; k--) cout << s1[k]; // write s1 backwards
for (int k=s1.size()-1; k>=0; k--) s1[k] = 'a'; // change s to "aaaaa"
s[10] = 'a'; // ERROR! s only has 5
// chars
The specified size can be any expression that evaluates to a non-negative
integer value.
vector <int> v1(10); // v1 is a vector of 10 integers
vector <char> v2(5); // v2 is a vector of 5 characters
vector <int> v(10);
for (int k=0; k<10; k++) {
v[k] = 3;
}
vector <int> v1(10);
vector <double> v2(5);
cout << v1.size(); // v1's size is 10
cout << v2.size(); // v2's size is 5
vector <int> v(1);
v[0] = 10;
v.resize(2*v.size());
v[1] = 20;
v.resize(1);
The resize operation preserves as many of the old values as possible
(so in the example, after the first resize operation, v[0]
is still 10; after the second resize operation, v[0]
is still 10, but there is no element of v equal to 20).
vector <int> f( ) { ... }
void f( vector
"hello", "", "bye, "", "", "!"
then function NonEmpty should create and return a vector
that contains the 3 strings:
"hello", "bye, "!"
#include <iostream>
#include <vector>
int main() {
vector
When you run this program, the output should be:
vector size before calling Expand: 1
vector size after calling Expand: 2
vector size before calling Expand: 2
vector size after calling Expand: 4
vector size before calling Expand: 4
vector size after calling Expand: 8
vector size before calling Expand: 8
vector size after calling Expand: 16
[ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ]
Solutions to Self-Study Questions
int Length() const;
Note that Length should be a const member function
because it does not modify any fields.
int IntList:: Length() const {
return numItems;
}
IntList(int n, int v);
and the following would be added to IntList.C:
IntList::IntList(int n, int v): Items(new int[SIZE]), numItems(0),
arraySize(SIZE) {
for (int k=0; k<n; k++) AddToEnd(v);
}
Note that this version of the 2-argument constructor first initializes
the list to be empty (by setting numItems to zero), then uses the
AddToEnd function to add value v to the list n
times. Of course, the code that stores v in the Items
array could be included here instead of calling AddToEnd;
however, it is usually better to call a function than to duplicate code.