Task 1 (Template Class)
#include <iostream> using namespace std; // Definition of Class A class A{ public: A(int x0=0, int y0=0): x{x0}, y{y0} {} void show() const { cout << x << ", " << y << endl; } private: int x, y; }; // Definition of class B class B{ public: B(double x0, double y0): x{x0}, y{y0} {} void show() const { cout << x << ", " << y << endl;} private: double x, y; }; int main() { A a(3, 4); a.show(); B b(3.2, 5.6); b.show(); system("pause"); }
Looking at the code, you can see that class A and class B are the same except for the different types of data members. Class definitions are similar. Is there a mechanism to abstract the same parts from the definitions of a similar set of classes, and express the different parts in terms of changes? Class templates provide such a mechanism.
#include <iostream> #include <string> using namespace std; // Define Class Template X template <typename T> class X { public: X(T x0, T y0) : x{x0}, y{y0} {} void show() const { cout << x << ", " << y << endl; } private: T x, y; }; int main() { X<int> x1(3, 4); x1.show(); X<double> x2(3.2, 5.6); x2.show(); X<string> x3("hello", "c plus plus"); x3.show(); system("pause"); }
The advantage of using template classes is that they can be "specialized" into many specific classes. For example, code line23, which specializes a class template to a case where the data is a string class. Of course, there is also a precondition, provided that the code operations in the class templates are supported for these types of specialization. For example, the show() method of the code line10 class template X uses the output stream object cout and the insert operator < to output data. It must support the output operations of data of type int,doube, string. Otherwise, error messages will occur during template specialization.
Task 2 (string class)
String string in C++, strictly speaking, is not a real type, it's actually a template class basic_string The specialized form of the class. Using string = std::basic_ String<char>;
#include <iostream> #include <string> int main() { using namespace std; string s1, s2; s1 = "nuist"; // assignment s1[0] = 'N'; // Supports access through [] and indexing cout << boolalpha << (s1 == "nuist") << endl; // string comparison cout << s1.length() << endl; // String Length cout << s1.size() << endl; // String Length s2 = s1 + ", 2050"; // String Connection cout << s2 << endl; string email{"xyz@gmail.com"}; auto pos = email.find("@"); // Finds the index position for the first occurrence of the substring'@', and returns string::npos if it fails if (pos == string::npos) cout << "illegal email address"; else { auto s1 = email.substr(0, pos); // Substring from index 0 ~ pos-1 auto s2 = email.substr(pos + 1); // Substring from pos+1 to end cout << s1 << endl; cout << s2 << endl; } string phone{"15216982937"}; cout << phone.replace(3, 5, "*****") << endl; // Replace five consecutive characters starting at index position 3 with * string s3{"cosmos"}, s4{"galaxy"}; cout << "s3: " + s3 + " s4: " + s4 << endl; s3.swap(s4); // exchange cout << "s3: " + s3 + " s4: " + s4 << endl; string s5{"abc"}; const char *pstr = s5.c_str(); // Method c_str() converts string class string groups into C-style strings cout << pstr << endl; string s6{"12306"}; int x = stoi(s6); // Convert string to int cout << x << endl; system("pause"); }
#include <iostream> #include <string> #include <limits> int main() { using namespace std; string s1; cin >> s1; // Extracts a string from the input stream to s1, and ends when spaces, carriage returns, and tabs are encountered cout << "s1: " << s1 << endl; cin.ignore(numeric_limits<streamsize>::max(), '\n'); // Empty Input Buffer getline(cin, s1); // Extract a line of string from the input stream to s1 until it breaks cout << "s1: " << s1 << endl; string s2, s3; getline(cin, s2, ' '); // Extract string from input stream to s2 until delimiter space is specified getline(cin, s3); cout << "s2: " << s2 << endl; cout << "s3: " << s3 << endl; system("pause"); }
Combining code with run results, you can see:
- When entering a string object, CIN >> S1 defaults to spaces, carriage returns, Tab keys, etc. It does not support cases where a string contains spaces.
- Using getline(cin, s1), a string containing spaces can be read in. You can also specify a delimiter to read through parameters, such as code line18.
- Buffers are involved in both input and output. Try to remove line12, run the program again, and observe the results. Check the literature to see which scenarios require emptying the buffer.
#include <iostream> #include <string> int main() { using namespace std; string s; // Repeat typing the string, converting lowercase characters to uppercase until you press ctrl+Z while (getline(cin, s)) { for (auto &ch : s) ch = toupper(ch); cout << s << "\n"; } system("pause"); }
- Code line11, using getline(cin, s) as the loop condition for while, repeats the entry until the key Ctrl+Z is pressed to end the loop.
- Code line14, uses the standard library function toupper() to convert lowercase characters to > uppercase characters.
- line13, range for, and automatic type derivation, using the reference type here. Try changing the reference type to normal type, recompile and run the program, and see if the results are different? Consider and understand different types of flexible references in encoding based on running results.
Changing the reference type to a normal type does not change the original string.
Task 3 (vector template)
A vector is a dynamic array class template provided by the C++ standard library and can be seen as an ordered container encapsulating arrays of dynamic sizes.
- Characteristic
- It is safer than ordinary arrays.
- Compared to a fixed-size array class template array, the size of the array object is variable when vector s are used to specialize into a specific type of array class. Space is allocated on demand on the heap. Support random access.
- Application Scenarios
- Where the number of data items cannot be determined, and data items often need to be appended or deleted at the end
#include <iostream> #include <vector> template <typename T> void output(T x) { for (const auto &i : x) std::cout << i << ", "; std::cout << "\b\b \n"; } int main() { using namespace std; vector<int> v1; // Create a vector Object v1, no size specified, element is int, uninitialized vector<int> v2(5); // Create a vector Object v2 containing five elements, which are of type int and have an initial value of 0 as the default vector<int> v3(5, 42); // Creates a vector Object v3 containing five elements, which are of type int, with an initial value of 42 vector<int> v4{9, 2, 3, 0, 1}; // Create a vector Object v4 with an int element, using the Initialize List method vector<int> v5{v4}; // Create a vector Object v5, created with an existing Object v4 output(v2); output(v3); output(v4); output(v5); system("pause"); }
#include <iostream> #include <vector> int main() { using namespace std; vector<int> v{1, 9, 2, 5, 6}; // Traversal mode 1:Range for for (auto const &i : v) cout << i << ", "; cout << "\b\b \n"; // Traversal Mode 2: Using Iterators for (auto it = v.begin(); it != v.end(); ++it) cout << *it << ", "; cout << "\b\b \n"; // Traversal Mode 3: Using Reverse Iterator for (auto it = v.rbegin(); it != v.rend(); ++it) cout << *it << ", "; cout << "\b\b \n"; system("pause"); }
This code example traverses the output of the vectorobject v in three ways, all of which use automatic type inference auto. Among them, mode 2 uses an iterator and mode 3 uses a reverse iterator. begin(), end(), rbegin(), rend() are commonly used member functions of vectors. Where:
Member function | function |
---|---|
begin() | Returns an iterator pointing to the first element |
end() | Returns an iterator pointing to the position after the last element |
rbegin() | Return to last element |
rend() | Returns an iterator pointing to the position before the first element |
It appears to be similar to a pointer, accessed indirectly by an asterisk. However, iterators are abstractions and generalizations of pointers. Although it behaves like a pointer, it is not a pointer.
#include <iostream> #include <vector> int main() { using namespace std; vector<int> v1{42}; cout << "v1.size() = " << v1.size() << endl; cout << "v1.capacity() = " << v1.capacity() << endl; v1.push_back(55); // Add a data to the tail v1.push_back(90); cout << "v1.size() = " << v1.size() << endl; cout << "v1.capacity() = " << v1.capacity() << endl; for (auto i = 0; i < 8; ++i) v1.push_back(i); cout << "v1.size() = " << v1.size() << endl; cout << "v1.capacity() = " << v1.capacity() << endl; v1.pop_back(); // Delete a data from the tail cout << "v1.size() = " << v1.size() << endl; cout << "v1.capacity() = " << v1.capacity() << endl; system("pause"); }
Member function | function |
---|---|
size() | Returns the current number of elements |
capacity() | Returns the maximum number of elements that can be accommodated without space reallocation |
push_back() | Append element to tail |
pop_back() | Remove element from tail |
#include <iostream> #include <vector> #include <algorithm> #include <string> template <typename T> void output(const T &obj) { for (auto i : obj) std::cout << i << ", "; std::cout << "\b\b \n"; } int main() { using namespace std; vector<string> v{"music", "film"}; v.insert(v.begin(), "literature"); // Insert element before iterator v.begin() output(v); cout << v.at(1) << endl; //Returns the element with index 1. The at() method does index crossover checking compared to v[1]. v.erase(v.begin()); // Remove element at iterator v.begin() position output(v); v.push_back("literature"); v.push_back("art"); output(v); reverse(v.begin(), v.end()); // Flip over elements in v (reverse order) output(v); sort(v.begin(), v.end()); // Sort elements in v in ascending order output(v); system("pause"); }
Combining the code with the results of the run, you can see that in this code:
- Insert elements before the specified iterator position in the container using method insert(), and remove elements that specify > iterator position using method erase();
- reverse() in the algorithm library is used to flip data items in container object v1. Sort data items in V1 in ascending order using sort().
Task 4 (array template)
Array is a fixed-size array class template provided by the C++ standard library.
- Characteristic
- It is safer than ordinary arrays. At the same time, there is no deterioration in efficiency.
- Compared to the dynamic array class template vector, the size of the array object created is fixed when array is specialized to a specific type of array class.
- Support random access.
- Application Scenarios
Generally, if the number of elements is fixed, array s are safer and more efficient than vector s.
#include <iostream> #include <array> template <typename T> void output(T const &obj) { for (auto i : obj) std::cout << i << ", "; std::cout << "\b\b \n"; } int main() { using namespace std; array<int, 5> x1; // Define array object x1, containing five int elements, uninitialized x1.fill(42); // Fill each element of the array object x1 with 42 x1[0] = 999; // Support random access through subscripts; No cross-border check x1.at(1) = 666; // Support access to index through at method; For cross-border checking, an exception is reported when the index crosses the boundary output(x1); array<int, 5> x2{}; // Defines the array object x2, which contains five int elements and is initialized to zero output(x2); array<int, 5> x3{9, 2, 1, 0, 7}; // Defines the array object x3, which contains five int elements and is initialized to the specified value output(x3); system("pause"); }
- Use the template class array to define the method of the object. Since arrays are fixed-size array classes, you must specify type parameters and number of elements when constructing objects. Supports initialization of array object elements. For example, line16, line22, line25.
- Support random access, such as line10-11. Instead of checking for index boundaries in [] mode, at() method will check for index boundaries beyond which an exception will be reported.
- Array object elements are populated using the method fill provided by the array class template. Such as line9.
#include <iostream> #include <array> #include <string> int main() { using namespace std; array<string, 5> names{"Bob", "Alice", "Leo"}; names.at(3) = "Bill"; names.at(4) = "Nancy"; for (auto it = names.begin(); it != names.end(); ++it) cout << *it << ", "; cout << "\b\b \n"; for (auto it = names.rbegin(); it != names.rend(); ++it) cout << *it << ", "; cout << "\b\b \n"; system("pause"); }
This code uses the at() method to access the elements of object names through an index. line14-20, uses iterators, reverse iterators, and automatic type derivation to iterate through the string array object names.
Task 5 (LIveShow)
The problem scenario is described below:
An independent musician is hosting a small free live show. livehouse is limited in capacity to accommodate up to 100 music fans. Online booking registration is now open through a platform. Online booking registration information class Info is as follows:
- Data Members
- Nickname
- Contact
- City of your residence
- Number of scheduled attendees (n)
- Function members
- Constructor
With parameters to initialize booking information (nickname, contact, city, number of scheduled attendees) - print()
Print information (nickname, contact information, city, number of people scheduled to attend)
- Constructor
- Write code to achieve the following requirements:
- Designs and implements an information class Info for recording the registration audience information. The class definition is saved in the file info.hpp
- Write the main function file task5.cpp:
- Define a vector class object, audience_info_list, to store the audience information for online booking registration;
- Define a const constant capacity to hold the maximum number of audiences a live house can hold
- Enter each reservation registration information from the keyboard until it stops (press Ctrl+Z, or you can program your own other
Stop typing) or the maximum number of scheduled attendees is reached, output audience_ Info_ All Reserved Audiences in List Object
Interest. - When a user makes an appointment, prompts the user to enter q to quit when the number of scheduled attendees exceeds the remaining capacity of the livehouse site.
Or, enter u to update the reservation information. - Print audience information for an appointment to a live house
ReserveInfo.cpp
#include <iostream> #include <vector> #include <string> #include <iomanip> using namespace std; // Reservation Class class ReserveInfo { private: string nick_name; string contact; string city; int reserve_num; public: ReserveInfo(); ReserveInfo(string nick_name, string contact, string city, int reserve_num); ~ReserveInfo(); int get_reserve_num() const; void print(); }; ReserveInfo::ReserveInfo() { } ReserveInfo::ReserveInfo(string nick_name, string contact, string city, int reserve_num) : nick_name(nick_name), contact(contact), city(city), reserve_num(reserve_num) { } ReserveInfo::~ReserveInfo() { } int ReserveInfo::get_reserve_num() const { return reserve_num; } void ReserveInfo::print() { cout << left << endl << setw(15) << "\n Salutation:" << setw(15) << nick_name << setw(15) << "\n Contact information:" << setw(15) << contact << setw(15) << "\n City:" << setw(15) << city << setw(15) << "\n Reservations:" << setw(15) << reserve_num << endl; }
LiveShow.cpp
#include <iostream> #include <vector> #include <string> #include <iomanip> #include "ReserveInfo.cpp" using namespace std; // Live Performance Category class LiveShow { private: vector<ReserveInfo> reserve_list; const int capasity = 100; public: LiveShow(); ~LiveShow(); int get_capacity_remain(); void add_reserve(); void print(); }; LiveShow::LiveShow() { } LiveShow::~LiveShow() { } int LiveShow::get_capacity_remain() { int capacity_remain = capasity; for (auto const reserve_info : reserve_list) { capacity_remain -= reserve_info.get_reserve_num(); } return capacity_remain; } void LiveShow::add_reserve() { cout << "Enter information:\n\n call/Nickname, Contact(mailbox/Cell-phone number),City, intended attendance\n"; string str_temp; while (cin >> str_temp) { string nick_name; string contact; string city; int reserve_num; nick_name = str_temp; cin >> contact >> city >> reserve_num; if (reserve_num > this->get_capacity_remain()) { char option; cout << "Dear " << nick_name << " Sorry, there are only" << this->get_capacity_remain() << "Locations." << "\n1. input u,To update(update)Booking Information" << "\n2. input q,Exit Reservation" << "Your choice:"; cin >> option; if (option == 'u') { continue; } if (option == 'q') { break; } }else{ ReserveInfo reserveInfo(nick_name, contact, city, reserve_num); reserve_list.push_back(reserveInfo); } } } void LiveShow::print() { for(auto reserve_info : reserve_list){ cout << "So far, there are a total of " << capasity-get_capacity_remain() << " The audience is scheduled to attend. The scheduled audience information is as follows:\n"; reserve_info.print(); } }
Test.cpp
#include <iostream> #include <vector> #include <string> #include <iomanip> #include "LiveShow.cpp" int main() { LiveShow liveShow_bth; liveShow_bth.add_reserve(); liveShow_bth.print(); system("pause"); }
test result
Task 6 (Encryption/Decryption)
A TextCoder class is designed and implemented for simple encryption and decryption of English text strings. Requirements are as follows
-
Data Members
text private, used to store strings to be encrypted or decrypted (English characters only inside strings) -
Function members
encoder() is public for encrypting data member texts to return encrypted English text as a return value
The encryption rules are as follows:Each letter is replaced with the fifth subsequent letter, that is:
Character a is replaced with f, character b with g, character u with z, character v with a, character Z with e
Change, and so on.
Capital character A is replaced with capital letter F, capital character B with capital letter G, and capital character Z with capital character E.
Characters other than letters remain unchanged.
abcdefghijklmnopqrstuvwxyzdecoder() is public and is used to decrypt data member texts to return the decrypted English text as a return value
The decryption rules are as follows:Each alphabetic character is replaced by its fifth preceding character, that is:
The characters f are replaced with a, g with b, a with v, B with w, and so on. (Uppercase class
Same)
Characters other than letters remain unchanged.
In the main program, loop in English text, use the TextCoder-like construction object to complete the encryption operation, and decrypt the encrypted text received after transmission. Until you press Ctrl+Z to terminate the program.
TextCoder.cpp
#include <iostream> #include <vector> #include <string> #include <iomanip> using namespace std; class TextCoder { private: string text; public: TextCoder(); TextCoder(string text); ~TextCoder(); void set_text(string text); string get_text(); string encoder(); string decoder(); }; TextCoder::TextCoder() { } TextCoder::TextCoder(string text) : text(text) { } TextCoder::~TextCoder() { } void TextCoder::set_text(string text) { this->text = text; } string TextCoder::get_text() { return text; } string TextCoder::decoder() { string text_decoded = text; for (int i = 0; i < text_decoded.length(); i++) { if (text_decoded[i] >= 65 && text_decoded[i] <= 90) { text_decoded[i] = 90 - (90-text_decoded[i] + 5)%26; }else if(text_decoded[i] >= 97 && text_decoded[i] <= 122){ text_decoded[i] = 122 - (122-text_decoded[i] + 5)%26; } } return text_decoded; } string TextCoder::encoder() { string text_encoded = text; for (int i = 0; i < text_encoded.length(); i++) { if (text_encoded[i] >= 65 && text_encoded[i] <= 90) { text_encoded[i] = (text_encoded[i]-65 + 5)%26 + 65; }else if(text_encoded[i] >= 97 && text_encoded[i] <= 122){ text_encoded[i] = (text_encoded[i]-97 + 5)%26 + 97; } } return text_encoded; }
Test.cpp
#include "TextCoder.cpp" #include <iostream> #include <string> int main() { using namespace std; string text, encoded_text, decoded_text; cout << "Enter English text: "; while (getline(cin, text)) { encoded_text = TextCoder(text).encoder(); // Temporary anonymous object used here cout << "Encrypted English text:\t" << encoded_text << endl; decoded_text = TextCoder(encoded_text).decoder(); // Temporary anonymous object used here cout << "Decrypted English Text:\t" << decoded_text << endl; cout << "\n Enter English text: "; system("pause"); } }
Test results: