////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // Copyright -C- 1997, by Richard E. Pattis // // Class Name : Vector // // Classification : Templated Class // // Files : Declaration - vector.h // Definition - vector.cpp // // Author : Richard E. Pattis // Computer Science Department // Carnegie Mellon University // 5000 Forbes Avenue // Pittsburgh, PA 15213-3891 // e-mail: pattis@cs.cmu.edu // // Maintainer : Author // // // Description: // // A templated Vector class combines all the advantages of a C/C++ raw array // (which we will learn about later) with a struct that contains an array and // its allocated/used size. Basically, we can use this templated class to // construct an array object and access its homogenous members. For example, // we can declare // // Vector V(10); // // to construct an object V with 10 int members (numbered 0-9). Note how we // instantiate the Vector class with a member type int: Vector. We can // then access the members in this object just like an array: e.g., V[4]. By // carefully seting Used of the array to the right value, we can ensure that // all member accesses are legal. // // Another advantage of this class is that the number of members can be // programmed to grow or shrink. So, we don't need to know how big an array // is at compile time, but can re-size it as necessary during runtime. // // Note the ~Vector is a destructor. It is called automatically by C++ for // an object of the Vector when its scope is exited. This function must // reclaim all the storage the array uses. For example // { // Vector V(10); //Constructor for V is called explicitly // Vector X(5); //Constructor for X is called explicitly // ... // } //Destructor for V and X is called implicitly // // // Known Bugs : None // // Future Plans : None // // History: // 3/ 4/97: R. Pattis - Operational // 10/12/97: R. Pattis - Altered some code dealing with Size/Used // ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // // Declarations // ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// //When we instantiate the templated Vector class, we specify a Member_Type, which // is the name of a type (or class). Each member of the vector is a value of // this type or class. #ifndef __Vector__ //Do not duplicate in a compilation #define __Vector__ #include using namespace std; template class Vector { /////// public: /////// //Constructors & Destructors Vector (); //Default Constructor explicit Vector (int Size); Vector (const Vector& V); ~Vector( ); //Assignment const Vector& operator = (const Vector& RHS); //Accessors int Size () const; int Used () const; const Member_Type& operator[] (int I) const; bool Is_Full () const; //Mutators Member_Type& operator[] (int I); void Fill_With (const Member_Type& Value); void Set_Size (int New_Size); void Set_Used (int New_Used); void Set_Size_From_Used (); void Set_Used_From_Size (); void Append (const Member_Type& New_Value); //////// private: //////// int my_Size; int my_Used; Member_Type* my_Values; }; template bool operator== (const Vector& Left, const Vector& Right); template bool operator!= (const Vector& Left, const Vector& Right); template ostream& operator<<(ostream& OS, const Vector& V); //Template classes must include their code, so this .h file includes the .cpp //file automatically; for this reason there is no compiled version of the .cpp //file in the 15-127 class library (or any project) #include "vector.cpp" #endif ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // // Semantics // // Advice for Member_Type // 1) Should be primitive/struct or a class with a default constructor // 2) Should have = (assignment) defined, and == and != relational operators // 3) Should have operators<< overloaded, inserting onto the console stream // Otherwise you can get a compiler error when this class is instantiated // (if you try to use a member/operator that depends on such a property) // // // Vector V(10); // // V Vector // +---------------------------------------------------------------+ // | my_Values 0 1 2 3 4 5 6 7 8 9 | // | +-----------+ +---+---+---+---+---+---+---+---+---+---+ | // | | ------+--->| ? | ? | ? | ? | ? | ? | ? | ? | ? | ? | | // | +-----------+ +---+---+---+---+---+---+---+---+---+---+ | // | | // | my_Size | // | +-----------+ | // | | 10 | | // | +-----------+ | // | | // | my_Used | // | +-----------+ | // | | 0 | | // | +-----------+ | // | | // +---------------------------------------------------------------+ // // Because the Vector class was instantiated with int as the Member_Type, all the // members in the Vector are unintialized; if Member_Type were a class, the // default constructor defined for that class would initialize every member in // the Vector. // // // Class Invariants: // my_Size = Allocated size of array pointed to by my_Values // my_Used <= my_Size (can use some or all of allocated array) // // // Vector (); // Pre : None // Post : Object constructed with Size() = 0; Used() = 0 // Note : This constructor is useful if you want to declare a Vector in // some scope, but not specify its size until later (e.g., Set_Size): // for example, you might declare the Vector in the main function, // and then pass it to a Read function which opens a file that // specifies the needed size, or just keeps reading value from the // file and calling the Append function to set its size // This constructor is also necessary to declare Vectors of Vectors // // // Vector (const Vector& V); // Pre : None // Post : Object is copy of V (same Size, Used, V[0] through V[Used()-1]) // // // explicit Vector (int Size); // PreExc : Size >= 0; throws invalid_argument // Post : Object constructed with Size() = Used; Used() = 0 // // // ~Vector( ); // Pre : None // Post : All memory allocated for Vector is deallocated // // // const Vector& operator = (const Vector& RHS); // Pre : None // Post : Object is copy of RHS (same Size, Used, V[0] through V[Used()-1]) // // // int Size () const; // Pre : None // Post : Returns current size of array // // // int Used () const; // Pre : None // Post : Returns amount of array being used // Note : This value is the one checked by [] so it appears in the upper // bound of for loops // // // const Member_Type& operator[] (int I) const; // PreExc : 0 <= I <= Used()-1; throws invalid_argument // Post : Returns value stored in the Ith member of this Vector // Note : This operator throws an exception based on Used() not Size() // // // bool Is_Full () const; // Pre : None // Post : Returns whether Used() is the same as Size() // // // Member_Type& operator[] (int I); // PreExc : 0 <= I <= Used()-1; throws invalid_argument // Post : Returns the storage location of the Ith member of this Vector // (used to store a new value in the Ith member of this Vector) // Note : This operator throws an exception based on Used() not Size() // Example: V[2] = 0; // // // void Fill_With (const Member_Type& Value); // Pre : none // Post : Fills V[0] through V[Used()-1] with Value // // // void Set_Size (int New_Size); // PreExc : Used() <= New_Size; throws invalid_argument // Post : Size() = New_Size // Note : Increases or decreases Size, but not below Used() // // // void Set_Used (int New_Used); // PreExc : 0 <= New_Used <= Size(); throws invalid_argument // Post : Used() = New_Used // Note : Increase or decreases Used, but not below 0 or above Size() // // // void Set_Size_From_Used (); // Pre : None // Post : Size is set to Used(); Vector is now an exact fit // // // void Set_Used_From_Size (); // Pre : None // Post : Used is set to Size(); Vector is now an exact fit // // // void Append (const Member_Type& New_Value); // Pre : None // Post : New_Value is stored in V[Used()], and it becomes the last used // member: e.g., Used() increases by 1 // If Used() = Size(), the latter increases by 1 first // Note : Append is a good way to put a new value into the Vector // (e.g., when reading values from a file into a vector) // // // ostream& operator<<(ostream& OS, const Vector& V); // Pre : operator<< must be overloaded for Member_Type; compilation error // Post : Displays members in [] separated by commas, suffixed by (Size = ...) // Example: Vector V(5); // V.Set_Used (3); //Using 3 members // V.Fill_With(8); //Fill these 3 members // cout << V; prints [8,8,8] (Size = 5) // Note : From this we can infer V.Used() is 3 (because 3 eights appear) // ////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////