CSCI 1730 Programming Project 7 Summer 2009 Hierarchy of Set Classes This program is due by midnight on ### Thursday, July 30. ### In this assignment you will define and implement public set classes BSet and StringSet< >. Also, you will redefine your class NSet from Project 6B so as to be a subclass of BSet, but otherwise changing NSet as little as possible. BSet will serve as a base class for the hierarchy; it will contain some but not all of the features of NSet. StringSet< > will be a subclass of BSet. For StringSet to make sense (and to compile) the class T will need to contain public members, specified below, which allow for a translation between a fixed set of strings and {0, 1, 2, ..., k-1}, where k is the number of strings in the set. Your code may make use of arrays and other basic C++ language features, and most C++ Standard Library components such as those declared in , , and . However since your classes are special types of containers you must never reference C++ Standard Library components for container classes (declared in , , , , , , , , or ). =============================== BSet ====================================== Class BSet is to be a concrete class which represents an arbitrary set of nonnegative integers. It is more basic than NSet in that it does not include any functions which require arithmetic operations on members. The required public functions for BSet, with their intended behaviors, are as follows. All are to be member functions of BSet if possible. Constructors: supply a default constructor which creates an empty set, a copy constructor, and a constructor such that for any integer n >= 0, BSet( n ) creates the set of natural numbers which are < n, i.e., the set {0, 1, ..., n-1}. If n < 0 then BSet( n ) should throw an exception of type out_of_range. Destructor: supply a destructor which deallocates any dynamically allocated memory. Accessors: overload the stream insertion operator << so as to accept an object of type BSet and insert/display the elements of the set in increasing order, 8 to a line. In case the set is empty, insert/display the string "(empty Set)". Also supply functions which perform as follows for an arbitrary object myset of type BSet and arbitrary n >= 0. If an argument n < 0 is passed then an exception of type out_of_range should be thrown. myset.card( ) returns the cardinality of myset. myset.minelt( n ) returns the smallest element of myset which is >= n, or -1 if there is no such element. The default for n should be 0, so that myset.minelt( ) returns the same value as myset.minelt( 0 ). myset.maxelt( n ) returns the largest element of myset which is <= n, or -1 if there is no such element. With no argument myset.maxelt( ) should return the largest element of myset, or -1 if there is no such element. myset.display( ) displays to standard output the contents of myset in the same format as the overloaded << operator. NOTE: this is a change from Project 6. *** Also, make display( ) virtual. *** Overload [ ] so that myset[ n ] returns true if n is an element of myset and false if not. Comparators: declare overloaded operators which are intended to perform as follows for arbitrary objects lset and rset of type BSet. lset <= rset is true iff lset is a subset of rset. lset >= rset is true iff lset is a superset of rset. lset == rset is true iff lset is equal to rset. Mutators: supply an overloaded stream extraction operator >>. This should convert any sequence of natural numbers separated by whitespace into a BSet. Supply overloaded operators which perform as follows for arbitrary objects lset and rset of type BSet, and arbirary n >= 0. If an argument n < 0 is passed then an exception of type out_of_range should be thrown. lset = rset replaces lset with a new copy of rset. lset |= rset replaces lset with the union of lset and rset. lset &= rset replaces lset with the intersection of lset and rset. lset -= rset replaces lset with the difference lset minus rset. lset ^= rset replaces lset with the symmetric difference of lset and rset. lset |= n adds n to lset (so no change to lset if it already contains n). lset -= n removes n from lset (so no change to lset if it doesn't contain n to begin with). lset ^= n toggles the membership of n in lset (nonmember to member and vice versa); =============================== NSet ====================================== Class NSet should behave exactly as it did for Project 6B *** except as noted here. One change is that the overloaded conversion operator (from Nset to NSet) should be omitted. Instead, supply a constructor which creates an NSet from a BSet.*** However, NSet is to be implemented as a subclass of BSet, so inherit all functionality specified for BSet. You can just move most of the implementations from Project 6B to BSet. Leave the implementations for the overloaded versions of += and *= in NSet. Do add the feature that if an integer argument n < 0 is passed to += or *= then an exception of type out_of_range is to be thrown. =========================== StringSet< > ================================== Class StringSet is to be a subclass of BSet which represents an arbitrary subset of a fixed set of strings determined by the class T. For StringSet to make sense (and to compile) the class T will need to contain public static member functions usize( ), toa( ) and toi( ). These are to allow for a 1-1 translation between a fixed set of strings of cardinality usize( ) and the set of nonnegative integers < usize( ). For purposes of discussion call this set of strings Tsset. Then T::usize( ) simply returns the cardinality of Tsset. For any C-style (null terminated) string tstring, T::toi( tstring ) is to throw an exception of type invalid_argument if tstring is not a member of Tsset. If it is a member of Tsset then T::toi( tstring ) should return a unique (to tstring) integer index i in the range 0 <= i < T::usize( ). Conversely, for any integer k in the range 0 <= k < T::usize( ), T::toa( k ) should return the unique string in Tsset which has index k. If k is not in this range then T::toa( k ) should throw an exception of type out_of_range. A class T with public members usize( ), toi( ) and toa( ) as described above we'll call "suitable". Note that the syntax for accessing static member functions in C++ is not the same as the syntax in Java. The "projects" sub-page of the course web site contains a link to a sample suitable class and tests of its public member functions, which are all static. For every suitable class T, the class StringSet is to be a class derived from BSet which represents arbitrary subsets of Tsset by way of the corresponding set of indices. This set of indices should be represented as a BSet object and manipulated, as far as possible, using member functions of BSet. Only the interface should deal with strings. The public members of Class BSet must all be adapted for the derived class StringSet. The necessary changes in behavior are described below. Constructor: the constructor taking an integer should just construct Tsset, no matter what value the argument takes. That is, StringSet( n ) should be the full set of cardinality T.usize( ). Accessors: the overloaded stream insertion operator << should accept an object of type StringSet and insert/display the elements of the set in increasing order (of index), one per line. In case the set is empty, insert/display the string "(empty Set)". The functions which perform accessor operations for an object myset of type StringSet and arbitrary n >= 0 should treat n as an index of an element of Tsset; the actual element (for instance, when an an element is returned) is a string. If an argument n < 0 is passed then an exception of type out_of_range should be thrown. myset.minelt( n ) returns the element of myset which has the smallest index >= n, or -1 if there is no such element. The default for n should be 0, so that myset.minelt( ) returns the same value as myset.minelt( 0 ). myset.maxelt( n ) returns the element of myset which has the largest index <= n, or -1 if there is no such element. With no argument myset.maxelt( ) should return the element of myset with the largest index, or -1 if there is no such element. myset.display( ) displays to standard output the contents of myset in the same format as the overloaded << operator. NOTE: this is a change from Project 6. Overload [ ] so that myset[ tstring ] returns true if tstring is an element of myset and false if not. If tstring is not a member of Tsset then myset[ tstring ] should throw an exception of type invalid_argument. Mutators: the overloaded stream extraction operator >> should convert any sequence of strings separated by whitespace into a StringSet, provided that each of the strings entered is in Tsset. If not, an exception of type invalid_argument should be thrown. The functions which perform mutator operations for an object myset of type StringSet by modifying the membership of some input parameter n should replace the integer n with a string tstring (say), and throw an exception of type invalid_argument if tstring is not a member of Tsset. Your project submission should include header files bset.h, numset.h, and strset.h (which has to declare and implement StingSet all in the same file, since it is templated). The other implementation files to submit are bset.cc, numset.cc, and a driver file proj7test.cc. Also submit a Makefile and a READ_ME file. Your Makefile should allow for separate compilation of object files bset.o, numset.o, and proj7test.o, along with linking the object files to produce an executable file proj7test. This executable file should include at least one test of each public member function of your Bset and StringSet classes. Your Makefile should compile and link everything when "make" is executed in your project directory. You may implement more functions than required. Remember to include a test for each public function you implement, whether or not the function is required. Some things to note: *The behaviors of the public member functions should be as described, so that the teaching assistant and the instructor can test your Nset class and its functions without editing your code. The same goes for the name of the class, the names of the files submitted, and the names of the executable files generated by the Makefile. *Develop this program following proper methodology, starting with a written plan. Develop the code one function at a time, with readable formatting, meaningful identifier names and illuminating comments. For each function, write the test code for it before writing the code for the function itself. *Design your class hierarchy to repeat or rewrite as little code as possible. In particular, all of the operations on sets which are needed for StringSet should be performed by member functions of BSet, aside from translating between strings and their indices. *The submission procedure and requirements common to all projects are described on a separate page which is linked from the course "projects" sub-page. Follow the submission procedure carefully. *Your programs must be written in C++. *Your programs should be robust and include appropriate error checks. *Your project should compile on "odin", or on "albany" or one of the other Linux workstations in the 307 lab, using g++ for GCC 4.1.2. Projects which compile properly will be scored out of 200 (if on time) based on (1) correctness of operation, (2) quality of design, (3) coding style and documentation of the source code, and (4) correctness and usefulness of the READ_ME file and the Makefile.