c2cpp lab3: Mdb with Classes
This assignment is worth 200 points total.
Please read this assignment carefully and follow the instructions EXACTLY.
Submission
Copyright By PowCoder代写 加微信 powcoder
Do NOT create any additional subdirectories. Work inside the existing part*/ subdirectories.
Note that certain part*/ directories contain symlinks (“symbolic links”) to files from previous parts;
this simply indicates that the file is the same as before, and that there’s no need to modify it further.
Ensure the Makefile for each part builds all executables when you run make .
Please refer to the lab submission instruction for other requirements.
Please check your code with valgrind . You will be penalized if you have any memory leaks or errors.
Part 0: Mdb without classes
Take a look in the part0/ directory at the provided C programs mdb-add.c and mdb-cat.c . Feel free to build them and test them; make sure you understand what they do and how they work. These are available as a reference for subsequent parts.
There’s nothing to submit for this part.
Example usage
$ ./mdb-add mdb
name please (will truncate to 15 chars): new
msg please (will truncate to 23 chars): msg
1: {new} said {msg}
$ ./mdb-add mdb
name please (will truncate to 15 chars): cool
msg please (will truncate to 23 chars): msg
2: {cool} said {msg}
Part 1: Implementing an Mdb class
Work from the part1/ directory for this part.
The skeleton code contains completed mdb-add.cpp and programs which make use of the uncompleted class Mdb in mdb.h . Implement this class so that and mdb-cat work correctly, like their C counterparts from Part 0 (with a few caveats, to be addressed in Part 2).
Requirements
Implement class Mdb ’s constructor, destructor, and member functions, as well as any global operator overloads, per their usage in mdb-add.cpp and mdb-cat.cpp .
Note that mdb.h additionally declares an operator<< overload for which must be defined. Formatting should mimic that of Part 0’s .
Decide whether to let the compiler generate the copy constructor and/or assignment for
Mdb , or delete them; do NOT define your own copy constructor and/or assignment (they are not used in the example programs).
Create mdb.cpp to house all definitions, except for the size and operator[] member functions; these should be defined inline in the class.
Note that mdb-add will create the database file if it doesn’t exist already. Keep this in mind when you implement class Mdb .
A new record added to an Mdb instance must be reflected both in-memory and in the associated file.
A user of class Mdb should not be able to modify any existing in-memory records (only add new ones).
We will use C file I/O in Part 1 and Part 2. We will switch over to C++ file streams in Part 3. You may NOT modify the data members of class Mdb , or add any additional data members.
mdb-cat.cpp
struct MdbRec
$ ./mdb-add mdb
name please (will truncate to 15 chars): jae woo
msg please (will truncate to 23 chars): mii
3: {jae woo} said {mii}
$ ./mdb-cat mdb
1: {new} said {msg}
2: {cool} said {msg}
3: {jae woo} said {mii}
The constructor will need to open the database file and read all records into the private
. The easiest way is to std::fopen with mode "a+b" for reading and appending,
then to the beginning before reading through the database file.
The Mdb only needs to read in the file once; don’t bother keeping up-to-date with any subsequent changes on the filesystem.
It’s okay if ./mdb-cat noexist_file creates a new file for this part; it’s not desired behavior, but this will be remedied in Part 2.
When C standard library functions fail, you should throw the following exception:
For your convenience, we provide a macro die that throws this exception. You’re welcome to use it if you’d like.
Whenever you feel an urge to use NULL , consider getting in the habit of using C++’s nullptr instead; it’s like NULL , but it enables stronger type-checking.
Part 2: Extending our use cases
Work from the part2/ directory for this part. Part 2a: Splitting the Mdb class
Assuming all went well in Part 1, your class Mdb implementation likely works fine for the average database file. But upon closer inspection, it’s evident that this model is a bit too inflexible; our Mdb constructor assumes the specified database file may be used for both reading and writing, so if we need to open a read-only file with mdb-cat , for example, this will fail despite that our intent is only to read. You may confirm this for yourself with chmod -w some_mdb ; ./mdb-cat some_mdb .
To remedy this, you’re going to split Mdb ’s reading and writing functionality into two separate classes MdbReader and MdbWriter , and have Mdb inherit from both of these.
std::vector
std::fseek
std::system_error(errno, std::generic_category(), "some msg")
MdbReader MdbWriter \/ \/ \/
Afterward, Mdb should work exactly as it did before, and is used the same in mdb-add.cpp . You’ll notice mdb-cat.cpp has been tweaked to use an instead of Mdb , but otherwise remains unchanged from Part 1. You should now be able to use on read-only files, and it should report if a file doesn’t exist (instead of creating it).
Requirements
You are only splitting existing functionality, so no members (except any necessary constructor(s)) should be added to any of the above classes. Only rearrange what was present in Part 1’s class Mdb .
You may, however, overload a function for the derived class Mdb which is already defined for one of its base classes, if necessary.
For each class, decide whether to leave the compiler-generated copy constructor and/or assignment, or delete them. Do not delete the compiler-generated copy constructor and/or assignment if they are safe.
As in Part 1, you should not define your own copy constructor and/or assignment anywhere.
class MdbWriter ’s constructor should take an additional optional boolean parameter to indicate whether an existing file should be overwritten or appended to; the default should be to overwrite.
class Mdb should only ever append, in accordance with the Part 1 behavior.
class MdbWriter by itself can be used to create a new database or to append to an existing one – it should not be storing any records in memory. We will see an example usage of MdbWriter in Part 2b.
Access control should be as narrow as possible. The data members that were private from Part 1 should be inaccessible to a user of any class here.
You should not have any redundant code across classes (including member variable declarations).
Note that, as stated earlier, function overloads for multiple classes are acceptable if necessary, but there should not be any redundant logic in their implementations.
The "+" in the mode is no longer recommended for this part, as you don’t need to open the same for both reading and writing; you should be opening the database file for reading and writing/appending separately.
Example usage
std::fopen
(continuing from last example)
$ ./mdb-cat noexist_file
mdb-cat: noexist_file: fopen: No such file or directory
$ chmod -w mdb
$ ./mdb-cat mdb
1: {new} said {msg}
2: {cool} said {msg}
3: {jae woo} said {mii}
Part 2b: Writing an mdb-grep program
Create a program mdb-grep which takes a pattern, an input database file path, and optionally an output database file path as arguments, performs a search on the input database for the RegEx pattern, and prints all matching records. If specified, these records should be written in the order they are found to the output database file.
Requirements
Implement in mdb-grep.cpp .
Print records with the same formatting as mdb-cat .
Must be able to use a read-only file for the input database.
Must overwrite any existing file for the output database (not append) if one is specified.
If an output database is specified and there were no matches, the resulting output database will be an empty file.
You should catch any std::exception and print cleanly, as done in mdb-add.cpp / mdb- cat.cpp .
This includes those thrown by standard library functions.
Should exit with non-zero status if nothing is matched or if an exception is thrown; otherwise exit with zero on success.
Update the Makefile so that mdb-grep is also built by default, and removed by the clean target.
std::regex_search will be helpful.
For handling the optional database file, you may find it simplest to construct the MdbWriter from "/dev/null" if no argument is provided (a special file for which all written data is discarded).
Example usage
(continuing from last example)
$ ./mdb-grep
usage: mdb-grep
$ ./mdb-grep msg mdb
1: {new} said {msg}
2: {cool} said {msg}
$ ./mdb-grep ‘.*oo’ mdb oowoo
2: {cool} said {msg}
3: {jae woo} said {mii}
$ ./mdb-grep ‘.*oo$’ mdb
3: {jae woo} said {mii}
$ ./mdb-grep ‘.*oo$’ oowoo
2: {jae woo} said {mii}
$ ./mdb-cat oowoo
1: {cool} said {msg}
2: {jae woo} said {mii}
$ # The following bash command shows that mdb-grep returns
$ # a non-zero exit code when there are no matching entries.
$ if ! ./mdb-grep noexist oowoo; then echo no match; fi
Part 2c: Move it or lose it
Study the provided mdb-add-multi.cpp program. To make it work, you must implement move construction.
Requirements
Implement the move constructor(s) for the appropriate base class(es).
Note that the compiler-generated move constructor of a class will call the move constructors of its base classes and its members.
All STL containers have move constructors defined already. Declare in ; define in .
Minimal copying of resources should take place.
Update the Makefile so that mdb-add-multi is also built by default, and removed by the clean target.
Example usage
(continuing from last example)
$ ./mdb-add-multi
database filename please (leave empty when done): mdb
database filename please (leave empty when done): mdb2
database filename please (leave empty when done): mdb3
database filename please (leave empty when done):
name please (will truncate to 15 chars): come in come in
msg please (will truncate to 23 chars): calling all mdbs
4: {come in come in} said {calling all mdbs}
1: {come in come in} said {calling all mdbs}
1: {come in come in} said {calling all mdbs}
$ ./mdb-cat mdb mdb2 mdb3
1: {new} said {msg}
2: {cool} said {msg}
3: {jae woo} said {mii}
4: {come in come in} said {calling all mdbs}
1: {come in come in} said {calling all mdbs}
1: {come in come in} said {calling all mdbs}
Part 3: Using C++ file I/O
Work from the part3/ directory for this part.
Copy over your ( std::fopen , existing
and from Part 2. Revise them to replace all instances of C file I/O , , etc.) with C++’s std::ifstream and std::ofstream . All
utilities should work as they did before.
std::fread
std::fwrite
Requirements
There should be no FILE * anywhere.
This includes the member you weren’t allowed to modify in previous parts; you should
replace it now.
Retain proper error-checking; e.g. mdb-cat should still report if a file doesn’t exist.
Define / overloads for an to / ,
operator<<
and use these in your updated
/ implementations.
operator>>
Declare in mdb.h ; define in mdb.cpp .
Don’t worry about error-checking inside these operators; let the caller be responsible for
checking the status of the stream afterward.
Remove any constructor/destructor/operator definitions (or deletions) if the compiler- generated versions are adequate.
Aside from replacing the stream member variable, you may NOT add additional members to any class.
Good luck!
Last updated: 2022-06-05
std::ofstream
std::ifstream
程序代写 CS代考 加微信: powcoder QQ: 1823890830 Email: powcoder@163.com