The document discusses classes, exceptions, and templates in C++. It covers two-dimensional arrays implemented as arrays of pointers to one-dimensional arrays. It also discusses class structure including data members, member functions, access control keywords like public and private, and usage of classes including constructors, destructor, and member functions. Initialization lists are introduced to initialize member variables that are classes without an assignment operator.
The document discusses classes, exceptions, and templates in C++. It covers two-dimensional arrays implemented as arrays of pointers to one-dimensional arrays. It also discusses class structure including data members, member functions, access control keywords like public and private, and usage of classes including constructors, destructor, and member functions. Initialization lists are introduced to initialize member variables that are classes without an assignment operator.
The document discusses classes, exceptions, and templates in C++. It covers two-dimensional arrays implemented as arrays of pointers to one-dimensional arrays. It also discusses class structure including data members, member functions, access control keywords like public and private, and usage of classes including constructors, destructor, and member functions. Initialization lists are introduced to initialize member variables that are classes without an assignment operator.
The document discusses classes, exceptions, and templates in C++. It covers two-dimensional arrays implemented as arrays of pointers to one-dimensional arrays. It also discusses class structure including data members, member functions, access control keywords like public and private, and usage of classes including constructors, destructor, and member functions. Initialization lists are introduced to initialize member variables that are classes without an assignment operator.
A two-dimensional array is implemented as an “array of arrays”. Two-dimensional array: an array of references (pointers) to one-dimensional arrays. § Classes Pascal’s Triangle: Class Structure A class consists of members: Data members (member variables): variables or constants. Member functions (methods): define behavior of the class. Example: Counter row i represents coefficients of (x+1)i class Counter { e.g. (x + 1)4 = 𝑥 4 + 4𝑥 3 + 6𝑥 2 + 4𝑥 + 1 public: // access control int** pascalTriangle(int n) { Counter( ); // initialization int** pt = new int*[n]; int getCount( ); // get the current count for (int i = 0; i < n; i++) { void increaseBy(int x); // add x to the count pt[i] = new int[i+1]; private: // access control pt[i][0] = 1; // left 1 int count; // the counter’s value for (int j = 1; j < i; j++) { }; // middle values Definitions of member functions pt[i][j] = pt[i-1][j-1] + pt[i-1][j]; Counter::Counter( ) // constructor } {count = 0;} pt[i][i] = 1; // right 1 int Counter::getCount( ) // get current count } {return count;} return pt; void Counter::increaseBy(int x) // add x to the count } {count += x;} 3-1 Usage void setMonth(int m) { Counter ctr; // an instance of Counter month = m; cout << ctr.getCount( ) << endl; } // prints the initial value 0 public: ctr.increaseBy(3); // increase by 3 Date(int month, int day) { cout << ctr.getCount( ) << endl; // prints 3 [Implementation with error-checking code here.] ctr.increaseBy(5); // increase by 5 } cout << ctr.getCount( ) << endl; // prints 8 }; Note: if no access specifier is given, the default is private for classes and public for execution: structures. Date d(10, 12); d.day = 26; // Failed The “public” AND “private” Keywords d.setMonth(4); // Failed again public: anyone can access. private: method or field is invisible & inaccessible to other classes. Member Functions → Instance variables are normally declared private and methods are normally Two major categories: declared public. Accessor functions: only read class data, with ”const”. Why use “private”? Update functions: can alter class data. To prevent data from being corrupted by other classes. Example: Passenger You can improve the implementation without causing other classes that depend on class Passenger { it to fail. public: e.g. Passenger( ); // constructor class Date { //In-class function private: bool isFrequentFlyer( ) const {return isFreqFlyer;} int day; void makeFrequentFlyer(const string& newFreqFlyerNo); int month; private: //… string name; 3-2 MealType mealPref; name = nm; bool isFreqFlyer; mealPref = mp; string freqFlyerNo; isFreqFlyer = (ffn != “NONE”); // true only if ffn is given }; freqFlyerNo = ffn; } void Passenger::makeFrequentFlyer(const string& // copy constructor newFreqFlyerNo) { Passenger::Passenger(const Passenger& pass) { isFreqFlyer = true; name = pass.name; freqFlyerNo = newFreqFlyerNo; mealPref = pass.mealPref; } isFreqFlyer = pass.isFreqFlyer; freqFlyerNo = pass.freqFlyerNo; Constructors } Passenger( ); // default constructor Passenger(const string& nm, MealType mp, const string& Usage ffn=“NONE”); // “NONE” is default argument Passenger P1; // default constructor Passenger(const Passenger& pass); // copy constructor Passenger P2(“John Smith”, VEGETARIAN, “293145”); Definitions of constructors // 2nd constructor Passenger::Passenger( ) { // default constructor Passenger P3(“Peter Jackson”, REGULAR); name = “--NO NAME-- ”; // not a frequent flyer mealPref = NO_PREF; Passenger P4(P3); // copied from P3 isFreqFlyer = false; Passenger P5 = P2; // copied from P2 freqFlyerNo = “NONE”; Passenger* PP1 = new Passenger; // default constructor } Passenger* PP2 = new Passenger(“John Blow”, NO_PREF); // constructor given member values // 2nd constructor Passenger::Passenger(const string& nm, MealType mp, const Passenger pa[20]; // default constructor string& ffn) { 3-3 Initializer List: to deal with initialization of member variables that are classes size = n; (without an assignment operator, =) : member_name(initial_value), … data = new int[n]; // allocate array Rewrite the 2nd Passenger constructor: } Passenger::Passenger(const string& nm, MealType mp, const string& ffn) : name(nm), mealPref(mp), isFreqFlyer(ffn != Vect::~Vect( ) { // destructor “NONE”) { freqFlyerNo = ffn; } delete [ ] data; // free the allocated array } Destructors The destructor for a class T is denoted as ~T: no arguments and no return type. Memory Allocation Example Using Vect class: class Vect { Vect a(100); // a is a vector of size 100 public: Vect b = a; // initialize b from a (DANGER!) Vect( ); // default constructor Vect c; // c is a vector (default size 10) Vect(int n); // constructor, given size c = a; // assign a to c (DANGER!) ~Vect( ); // destructor Shallow copy: a shallow copy of an object (collection, or class) copies all of the private: member field values, i.e., a copy of the class structure, not the elements. With a int* data; // an array shallow copy, two collections share the individual elements. int size; // number of array entries Vect b = a sets b.data = a.data (pointer copy) }; c = a lost the pointer to c’s original 10-element array. → memory leak a, b, and c all have members that point to the same array. Vect::Vect() { // default constructor Copy constructor: for a class T → T(const T& t) size = 10; Deep copy: data = new int[10]; // copy constructor from a } Vect::Vect(const Vect& a) { size = a.size; // copy size Vect::Vect(int n) { // constructor with given size data = new int[size]; // allocate new array 3-4 for (int i = 0; i < size; i++) { The “friend” keyword data[i] = a.data[i]; // copy the contents to access protected and private member data of other classes. } Friend function: } class SomeClass { // assignment operator from a private: Vect& Vect::operator=(const Vect& a) { int secret; if (this != &a) { // avoid self-assignment public: delete [ ] data; // delete old array friend ostream& operator<<(ostream& out, const SomeClass& size = a.size; // set new size x); // give << operator access to secret data = new int[size]; // allocate new array }; for (int i = 0; i < size; i++) { ostream& operator<<(ostream& out, const SomeClass& x) data[i] = a.data[i]; // copy the contents { cout << x.secret; } } Multiple classes: } class Humidity; return *this; class Temperature { } private: For any instance of a class object, “this” is defined to be the address of this int m_nTemp; instance. public: Temperature(int nTemp) { m_nTemp = nTemp; } Every class that allocates its own objects using new should: friend void PrintWeather(Temperature& cTemperature, Define a destructor to free allocated objects. Humidity& cHumidity); Define a copy constructor, which allocates its own new member storage and }; copies the contents of member variables. class Humidity { Define an assignment operator, which deallocates old storage, allocates new private: storage, and copies all member variables. int m_nHumidity; public: 3-5 Humidity(int nHumidity) { m_nHumidity = nHumidity; } Vector Matrix::multiply(const Vector& v) { friend void PrintWeather(Temperature& cTemperature, Vector w; Humidity& cHumidity); for (int i = 0; i < 3; i++) }; for (int j = 0; j < 3; j++) w.coord[i] += a[i][j] * v.coord[j]; void PrintWeather(Temperature& cTemperature, Humidity& // access to coord of v allowed cHumidity) { return w; std::cout << "The temperature is " << cTemperature.m_nTemp } << " and the humidity is " << cHumidity.m_nHumidity << std::endl; Nesting Classes } class Book { public: Friend class class Bookmark { class Vector { // a 3-element vector //… (Bookmark definition here) public: //… }; private: //… (Remainder of Book definition) double coord[3]; }; friend class Matrix; // give Matrix access to coord Use Book::Bookmark to refer to this nested class. }; class Matrix { // a 3×3 matrix Interface of a Class public: Prototypes for public methods, Vector multiply(const Vector& v); plus descriptions of their behaviors. // multiply by vector v private: Abstract Data Type (ADT) double a[3][3]; A class with a well-defined interface, but implementation details are hidden from }; other classes. 3-6 Invariant § Exceptions A fact about a data structure that is always true. When a run-time error occurs in C++: it ”throws an exception” (Exception object). e.g, “A Date object always represents a valid date.” Prevent the error by “catching” the Exception. Purpose: surviving errors Not all classes are ADTs! Some classes just store data (no invariants). By catching exceptions, you can recover from an unexpected error. e.g.: try to open a file that doesn’t exist. You can catch exception, print error STL Vector Class message, and continue. A vector can be resized dynamically. try { Each instance of an STL vector can only hold objects of one type. fin.open(“~esoe/ds/exam.pdf”, ios::in); Example: getline(fin, str, ‘\n’); #include <vector> //… using namespace std; } catch (FileNotFoundException& e1) { vector<int> scores(100); // 100 integer scores cout << “Error msg … ”; vector<char> buffer(500); // buffer of 500 characters } vector<Passenger> passenList(20); // list of 20 Passengers catch (IOException& e2) { fin.close( ); int i = 12; } cout << scores[i]; // index (range unchecked) What does this code do? buffer.at(i) = buffer.at(2*i); // index (range checked) (a) Executes the code inside “try”. (b) If “try” code executes normally, skip “catch” clauses. vector<int> newScores = scores; (c) If “try” code throws an exception, do not finish the “try” code. Jumps to first // copy scores to newScores “catch” clause. “Matches” exception object thrown is the same class/subclass of scores.resize(scores.size() + 10); exception type in “catch” clauses. // add room for 10 more elements When the “catch” clause finishes executing, jumps to the next line of code after all catch clauses. 3-7 Only the first matching “catch” is executed. Exception specification Each “catch” clause is called an exception handler. When we declare a function, we should also specify the exceptions it might throw. Use “catch (…)” to catch all exceptions. → last handler. void calculator( ) throw (ZeroDivide, NegativeRoot) { //… Exception constructors try { Exception types often form hierarchies. //… e.g.: one generic exception, MathException, representing all types of if (divisor == 0) mathematical errors. throw ZeroDivide(“Divide by zero in Module X”); class MathException { } public: catch (ZeroDivide& zde) { MathException(const string& err): errMsg(err) { } // handle division by zero. // constructor } string getError( ) {return errMsg;} catch (MathException& me) { // access error message // handle any math exception other than division by zero. private: } string errMsg; // error message //… }; } Using inheritance to define new exception types: If a function does not provide a “throw” specification, it may throw any exception. class ZeroDivide : public MathException { void fcn1( ); // can throw any exception public: void fcn2( ) throw( ); // can throw no exceptions ZeroDivide(const string& err): MathException(err) { } }; // divide by zero A generic exception class class NegativeRoot : public MathException { Serves as the “mother of all exceptions”. public: class RuntimeException { // Base class NegativeRoot(const string& err): MathException(err) { } private: }; // negative square root string errorMsg; 3-8 public: Class Templates RuntimeException(const string& err) {errorMsg = err;} A simple class template: string getMessage( ) const {return errorMsg;} template <typename T> }; class BasicClass { public: BasicClass(const T& t): myObj(t) { } // constructor § Templates T Get( ) const {return myObj;} Allow functions and classes to operate with generic types, to work on multiple void Set(const T& t) {myObj = t;} data types without being written for each one. private: Function Templates T myObj; e.g. minimum of two integers: }; int integerMin(int a, int b) {return (a < b ? a : b);} To instantiate a concrete instance of the class BasicClass, provide the class name A generic function for an arbitrary type T: followed by the actual type parameter enclosed in angled brackets (< … >). template <typename T> BasicClass<float> f; T genericMin(T a, T b) { Use typedef to make your code more readable: return (a < b ? a : b); typedef BasicClass<float> Float; } Float f(5.5f); cout << f.Get( ) << endl; The compiler looks at the argument types and determines which form of the function f.Set(12.3f); to instantiate. cout << f.Get( ) << endl; cout << genericMin(3, 4) << ‘ ‘ // = genericMin<int>(3, 4) typedef BasicClass<string> String; << genericMin(1.1, 3.1) << ‘ ‘ String s(“Steve”); // = genericMin<double>(1.1, 3.1) cout << s.Get( ) << endl; << genericMin(‘t’, ‘g’) << endl; s.Set(“Apple”); // = genericMin<char>(‘t’, ‘g’) cout << s.Get( ) << endl; 3-9