diff --git a/9781484200087_Exercise_Solutions/Chapter 1/Soln1_01.cpp b/9781484200087_Exercise_Solutions/Chapter 1/Soln1_01.cpp new file mode 100644 index 0000000..fce5430 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 1/Soln1_01.cpp @@ -0,0 +1,8 @@ +// Exercise 1.1 Writing the line "Hello World" to the screen. + +#include + +int main() +{ + std::cout << "Hello World" << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 1/Soln1_02.cpp b/9781484200087_Exercise_Solutions/Chapter 1/Soln1_02.cpp new file mode 100644 index 0000000..adb8831 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 1/Soln1_02.cpp @@ -0,0 +1,11 @@ +// Exercise 1.2 Write your name and age on successive lines. +// There are several possibilities. You can do it in one statement for example. +// You could also output '\n' to go to a new line. + +#include + +int main() +{ + std::cout << "Phile McCavity" << std::endl; // Name + std::cout << "Age: 88" << std::endl; // and age +) \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 1/Soln1_03.cpp b/9781484200087_Exercise_Solutions/Chapter 1/Soln1_03.cpp new file mode 100644 index 0000000..0d13cd6 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 1/Soln1_03.cpp @@ -0,0 +1,9 @@ +// Exercise 1.3 Spot the errors. The correct version should closely resemble the answer to exercise 1.1. + +include // # charaxcter missing before include + +Int main() // Should be int, not Int +{ + std:cout << "Hello World" << std:endl // A semicolon is missing from the end of this line + // cout and endl must be prefixed with std:: +) \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 10/Soln10_01/main.cpp b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_01/main.cpp new file mode 100644 index 0000000..01bbd60 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_01/main.cpp @@ -0,0 +1,13 @@ +// Exercise 10.1 Using multiple files and preprocessor directives. File: main.cpp +// We have seven files in all. +// The file main.cpp only needs to #include two of our three new header files, +// since all it does is call the functions printthis() and printthat(): + +#include "printthis.h" +#include "printthat.h" + +int main() +{ + print_this("This is a test string using printthis()."); + print_that("This is a test string using printthat()."); +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 10/Soln10_01/print.cpp b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_01/print.cpp new file mode 100644 index 0000000..32bc1f7 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_01/print.cpp @@ -0,0 +1,13 @@ +// Exercise 10.1 Using multiple files and preprocessor directives. File: print.cpp +// We have seven files in all. +// The file print.cpp contains the definition for the function print(). + +#include "print.h" +#include +#include +using std::string; + +void print(const string& s) +{ + std::cout << s << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 10/Soln10_01/print.h b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_01/print.h new file mode 100644 index 0000000..55d1cdb --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_01/print.h @@ -0,0 +1,14 @@ +// Exercise 10.1 Using multiple files and preprocessor directives. File: print.h +// We have seven files in all. +// The file print.h contains the prototype for the function print(). + +#ifndef PRINT_H +#define PRINT_H + +#include +using std::string; + +// Function prototype +void print(const string& s); + +#endif \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 10/Soln10_01/printthat.cpp b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_01/printthat.cpp new file mode 100644 index 0000000..8a234dd --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_01/printthat.cpp @@ -0,0 +1,12 @@ +// Exercise 10.1 Using multiple files and preprocessor directives. File: printthat.cpp +// We have seven files in all. +// The file printthat.cpp contains the definition for the function printthat(). +// Each of the files printthis.cpp and printthat.cpp must #include the file print.h, +// as well as its own header file: +#include "printthat.h" +#include "print.h" + +void print_that(const string& s) +{ + print(s); +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 10/Soln10_01/printthat.h b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_01/printthat.h new file mode 100644 index 0000000..65451d3 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_01/printthat.h @@ -0,0 +1,13 @@ +// Exercise 10.1 Using multiple files and preprocessor directives. File: printthat.h +// We have seven files in all. +// The file printthat.h contains the prototype for the function print_that(). +#ifndef PRINTTHAT_H +#define PRINTTHAT_H + +#include +using std::string; + +// Function prototype +void print_that(const string& s); + +#endif \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 10/Soln10_01/printthis.cpp b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_01/printthis.cpp new file mode 100644 index 0000000..de42d16 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_01/printthis.cpp @@ -0,0 +1,12 @@ +// Exercise 10.1 Using multiple files and preprocessor directives. File: printthis.cpp +// We have seven files in all. +// The file printthis.cpp contains the definition for the function printthis(). +// Each of the files printthis.cpp and printthat.cpp must #include the file print.h, +// as well as its own header file: +#include "printthis.h" +#include "print.h" + +void print_this(const string& s) +{ + print(s); +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 10/Soln10_01/printthis.h b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_01/printthis.h new file mode 100644 index 0000000..6bfde96 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_01/printthis.h @@ -0,0 +1,14 @@ +// Exercise 10.1 Using multiple files and preprocessor directives. File: printthis.h +// We have seven files in all. +// The file printthis.h contains the prototype for the function print_this(). + +#ifndef PRINTTHIS_H +#define PRINTTHIS_H + +#include +using std::string; + +// Function prototype +void print_this(const string& s); + +#endif \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 10/Soln10_02/main.cpp b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_02/main.cpp new file mode 100644 index 0000000..5c0c1fd --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_02/main.cpp @@ -0,0 +1,17 @@ +// Exercise 10.2 Using a global variable to count calls to print(). File: main.cpp +// Only this file and print.cpp are different from Ex 10.1. + +#include "printthis.h" +#include "printthat.h" + +#include // ADDED +extern int print_count = 0; // Counts calls to print() ADDED + +int main() +{ + print_this("This is a test string using printthis()."); + print_that("This is a test string using printthat()."); + + std::cout << "The print() function has been called a total of " // ADDED + << print_count << " times. " << std::endl; // ADDED +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 10/Soln10_02/print.cpp b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_02/print.cpp new file mode 100644 index 0000000..22e84c0 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_02/print.cpp @@ -0,0 +1,16 @@ +// Exercise 10.2 Using a global variable to count calls to print(). File: print.cpp +// Only this file and main.cpp are different from Ex 10.1. + +#include "print.h" +#include +#include +using std::string; + +extern int print_count; // ADDED + +void print(const string& s) +{ + std::cout << s << std::endl; + ++print_count; // ADDED + +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 10/Soln10_02/print.h b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_02/print.h new file mode 100644 index 0000000..4913b54 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_02/print.h @@ -0,0 +1,14 @@ +// Exercise 10.2 Using multiple files and preprocessor directives. File: print.h +// We have seven files in all. +// The file print.h contains the prototype for the function print(). + +#ifndef PRINT_H +#define PRINT_H + +#include +using std::string; + +// Function prototype +void print(const string& s); + +#endif \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 10/Soln10_02/printthat.cpp b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_02/printthat.cpp new file mode 100644 index 0000000..94f545d --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_02/printthat.cpp @@ -0,0 +1,12 @@ +// Exercise 10.2 Using multiple files and preprocessor directives. File: printthat.cpp +// We have seven files in all. +// The file printthat.cpp contains the definition for the function printthat(). +// Each of the files printthis.cpp and printthat.cpp must #include the file print.h, +// as well as its own header file: +#include "printthat.h" +#include "print.h" + +void print_that(const string& s) +{ + print(s); +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 10/Soln10_02/printthat.h b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_02/printthat.h new file mode 100644 index 0000000..bd1d588 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_02/printthat.h @@ -0,0 +1,13 @@ +// Exercise 10.2 Using multiple files and preprocessor directives. File: printthat.h +// We have seven files in all. +// The file printthat.h contains the prototype for the function print_that(). +#ifndef PRINTTHAT_H +#define PRINTTHAT_H + +#include +using std::string; + +// Function prototype +void print_that(const string& s); + +#endif \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 10/Soln10_02/printthis.cpp b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_02/printthis.cpp new file mode 100644 index 0000000..e63c4bc --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_02/printthis.cpp @@ -0,0 +1,12 @@ +// Exercise 10.2 Using multiple files and preprocessor directives. File: printthis.cpp +// We have seven files in all. +// The file printthis.cpp contains the definition for the function printthis(). +// Each of the files printthis.cpp and printthat.cpp must #include the file print.h, +// as well as its own header file: +#include "printthis.h" +#include "print.h" + +void print_this(const string& s) +{ + print(s); +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 10/Soln10_02/printthis.h b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_02/printthis.h new file mode 100644 index 0000000..467a23b --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_02/printthis.h @@ -0,0 +1,14 @@ +// Exercise 10.2 Using multiple files and preprocessor directives. File: printthis.h +// We have seven files in all. +// The file printthis.h contains the prototype for the function print_this(). + +#ifndef PRINTTHIS_H +#define PRINTTHIS_H + +#include +using std::string; + +// Function prototype +void print_this(const string& s); + +#endif \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 10/Soln10_03/main.cpp b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_03/main.cpp new file mode 100644 index 0000000..c0238a9 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_03/main.cpp @@ -0,0 +1,16 @@ +// Exercise 10.3 Using a global variable to count calls to print(). File: main.cpp +// This file is the same as Ex 10.2. + +#include "printthis.h" +#include "printthat.h" + +#include // ADDED +extern int print_count = 0; // Counts calls to print() ADDED + +int main(){ + print_this("This is a test string using printthis()."); + print_that("This is a test string using printthat()."); + + std::cout << "The print() function has been called a total of " // ADDED + << print_count << " times. " << std::endl; // ADDED +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 10/Soln10_03/print.cpp b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_03/print.cpp new file mode 100644 index 0000000..711e328 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_03/print.cpp @@ -0,0 +1,18 @@ +// Exercise 10.3 Using namespaces. The solution is as Exercise 10.2, with changes to +// print.h, print.cpp, printthis.cpp and printthat.cpp: + +// print.cpp +#include "print.h" +#include +#include +using std::string; + +void print1::print(const string& s) +{ + std::cout << s << " (Namespace name is print1.) " << std::endl; +} + +void print2::print(const string& s) +{ + std::cout << s << " (Namespace name is print2.) " << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 10/Soln10_03/print.h b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_03/print.h new file mode 100644 index 0000000..7d17e46 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_03/print.h @@ -0,0 +1,23 @@ +// Exercise 10.3 Using namespaces. The solution is as Exercise 10.2, with changes to +// print.h, print.cpp, printthis.cpp and printthat.cpp: + +// print.h +#ifndef PRINT_H +#define PRINT_H + +#include +using std::string; + +namespace print1 +{ + // Function prototype + void print(const string& s); +} + +namespace print2 +{ + // Function prototype + void print(const string& s); +} + +#endif \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 10/Soln10_03/printthat.cpp b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_03/printthat.cpp new file mode 100644 index 0000000..62ebe85 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_03/printthat.cpp @@ -0,0 +1,11 @@ +// Exercise 10.3 Using namespaces. The solution is as Exercise 10.2, with changes to +// print.h, print.cpp, printthis.cpp and printthat.cpp: + +// printthat.cpp +#include "printthat.h" +#include "print.h" + +void print_that(const string& s) +{ + print2::print(s); +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 10/Soln10_03/printthat.h b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_03/printthat.h new file mode 100644 index 0000000..26f08a0 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_03/printthat.h @@ -0,0 +1,14 @@ +// Exercise 10.2 Using multiple files and preprocessor directives. File: printthat.h +// We have seven files in all. +// The file printthat.h contains the prototype for the function print_that() +// and is the same as for Exercise 10.2. +#ifndef PRINTTHAT_H +#define PRINTTHAT_H + +#include +using std::string; + +// Function prototype +void print_that(const string& s); + +#endif \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 10/Soln10_03/printthis.cpp b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_03/printthis.cpp new file mode 100644 index 0000000..e6e3300 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_03/printthis.cpp @@ -0,0 +1,11 @@ +// Exercise 10.3 Using namespaces. The solution is as Exercise 10.2, with changes to +// print.h, print.cpp, printthis.cpp and printthat.cpp: + +// printthis.cpp +#include "printthis.h" +#include "print.h" + +void print_this(const string& s) +{ + print1::print(s); +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 10/Soln10_03/printthis.h b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_03/printthis.h new file mode 100644 index 0000000..9dbdcc0 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_03/printthis.h @@ -0,0 +1,15 @@ +// Exercise 10.3 Using multiple files and preprocessor directives. File: printthis.h +// We have seven files in all. +// This file printthis.h contains the prototype for the function print_this() +// and is the same as for Exercise 10.2. + +#ifndef PRINTTHIS_H +#define PRINTTHIS_H + +#include +using std::string; + +// Function prototype +void print_this(const string& s); + +#endif \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 10/Soln10_04/main.cpp b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_04/main.cpp new file mode 100644 index 0000000..f3139ba --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_04/main.cpp @@ -0,0 +1,25 @@ +// Exercise 10.4 More applications of preprocessor directives. + +// main.cpp +#include "printthis.h" +#include "printthat.h" + +//#define DO_THIS // uncomment to #define the token + +#ifdef DO_THIS +#define PRINT(val) print_this(#val); +#else +#define PRINT(val) print_that(#val); +#endif + +int main() +{ +#ifdef DO_THIS + print_this("This is a test string using printthis()."); +#else + print_that("This is a test string using printthat()."); +#endif + + std::cout << "The print() function has been called a total of " // ADDED + << print_count << " times. " << std::endl; // ADDED +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 10/Soln10_04/print.cpp b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_04/print.cpp new file mode 100644 index 0000000..cff7ebf --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_04/print.cpp @@ -0,0 +1,15 @@ +// Exercise 10.4 This file is the same as for Exercise 10.3. + +// print.cpp +#include "print.h" +#include +#include +using std::string; + +void print1::print(const string& s) { + std::cout << s << " (Namespace name is print1.) " << std::endl; +} + +void print2::print(const string& s) { + std::cout << s << " (Namespace name is print2.) " << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 10/Soln10_04/print.h b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_04/print.h new file mode 100644 index 0000000..caf2857 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_04/print.h @@ -0,0 +1,20 @@ +// Exercise 10.4 This file is the same as for Exercise 10.3. + +// print.h +#ifndef PRINT_H +#define PRINT_H + +#include +using std::string; + +namespace print1 { + // Function prototype + void print(const string& s); +} + +namespace print2 { + // Function prototype + void print(const string& s); +} + +#endif \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 10/Soln10_04/printthat.cpp b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_04/printthat.cpp new file mode 100644 index 0000000..0bf44cf --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_04/printthat.cpp @@ -0,0 +1,9 @@ +// Exercise 10.4 This file is the same as for Exercise 10.3. + +// printthat.cpp +#include "printthat.h" +#include "print.h" + +void print_that(const string& s) { + print2::print(s); +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 10/Soln10_04/printthat.h b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_04/printthat.h new file mode 100644 index 0000000..42d07b3 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_04/printthat.h @@ -0,0 +1,12 @@ +// Exercise 10.4 This file is the same as for Exercise 10.3. + +#ifndef PRINTTHAT_H +#define PRINTTHAT_H + +#include +using std::string; + +// Function prototype +void print_that(const string& s); + +#endif \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 10/Soln10_04/printthis.cpp b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_04/printthis.cpp new file mode 100644 index 0000000..eef5479 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_04/printthis.cpp @@ -0,0 +1,9 @@ +// Exercise 10.4 This file is the same as for Exercise 10.3. + +// printthis.cpp +#include "printthis.h" +#include "print.h" + +void print_this(const string& s) { + print1::print(s); +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 10/Soln10_04/printthis.h b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_04/printthis.h new file mode 100644 index 0000000..7f70f35 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 10/Soln10_04/printthis.h @@ -0,0 +1,15 @@ +// Exercise 10.4 Using multiple files and preprocessor directives. File: printthis.h +// We have seven files in all. +// This file printthis.h contains the prototype for the function print_this() +// and is the same as for Exercise 10.3. + +#ifndef PRINTTHIS_H +#define PRINTTHIS_H + +#include +using std::string; + +// Function prototype +void print_this(const string& s); + +#endif \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 11/Soln11_01/Integer.cpp b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_01/Integer.cpp new file mode 100644 index 0000000..0771877 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_01/Integer.cpp @@ -0,0 +1,15 @@ +// Exercise 11.1 Integer.cpp + +#include +#include "Integer.h" + +Integer::Integer(int m) +{ + n = m; + std::cout << "Object created." << std::endl; +} + +void Integer::show() +{ + std::cout << "Value is " << n << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 11/Soln11_01/Integer.h b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_01/Integer.h new file mode 100644 index 0000000..560c9ff --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_01/Integer.h @@ -0,0 +1,17 @@ +// Exercise 11.1 Integer.h + +#ifndef INTEGER_H +#define INTEGER_H + +class Integer +{ +private: + int n; + +public: + Integer(int m); + int getValue() {return n;} + void setValue(int m){ n = m; } + void show(); +}; +#endif \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 11/Soln11_01/Soln11_01.cpp b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_01/Soln11_01.cpp new file mode 100644 index 0000000..8e5b953 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_01/Soln11_01.cpp @@ -0,0 +1,27 @@ +// Exercise 11.1 Implementing an Integer class +#include +#include "Integer.h" + +int main() +{ + std::cout << "Create i with the value 10." << std::endl; + Integer i {10}; + i.show(); + std::cout << "Change value of i to 15." << std::endl; + i.setValue(15); + i.show(); + + std::cout << "Create j with the value 5000." << std::endl; + Integer j {5000}; + j.show(); + std::cout << "Set value of j to 150 times that of i." << std::endl; + j.setValue(150*i.getValue()); + j.show(); + + std::cout << "Create k with the value 789." << std::endl; + Integer k {789}; + k.show(); + std::cout << "Set value of k to sum of i and j values." << std::endl; + k.setValue(i.getValue()+j.getValue()); + k.show(); +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 11/Soln11_02/Integer.cpp b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_02/Integer.cpp new file mode 100644 index 0000000..1d92fce --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_02/Integer.cpp @@ -0,0 +1,45 @@ +// Exercise 11.2 Integer.cpp + +#include +#include "Integer.h" + +// Copy constructor +Integer::Integer(Integer& obj) : n(obj.n) +{ + std::cout << "Object created by copy constructor." << std::endl; +} + +// Constructor +Integer::Integer(int m) : n(m) +{ + std::cout << "Object created." << std::endl; +} + +void Integer::show() +{ + std::cout << "Value is " << n << std::endl; +} + +// Compare function +/* +int Integer::compare(const Integer obj) const +{ + if(n < obj.n) + return -1; + else if(n==obj.n) + return 0; + return 1; +} +*/ + +// Compare function with reference parameter +// /* +int Integer::compare(const Integer& obj) const +{ + if(n < obj.n) + return -1; + else if(n==obj.n) + return 0; + return 1; +} +// */ \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 11/Soln11_02/Integer.h b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_02/Integer.h new file mode 100644 index 0000000..bbc929b --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_02/Integer.h @@ -0,0 +1,20 @@ +// Exercise 11.2 Integer.h + +#ifndef INTEGER_H +#define INTEGER_H + +class Integer +{ +private: + int n; + +public: + Integer(int m = 0); + Integer(Integer& obj); // Copy constructor +// int compare(const Integer obj) const; // Compare function + int compare(const Integer& obj) const; // Compare function with reference paramter + int getValue() {return n;} + void setValue(int m){ n = m; } + void show(); +}; +#endif \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 11/Soln11_02/Soln11_02.cpp b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_02/Soln11_02.cpp new file mode 100644 index 0000000..d7fcb74 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_02/Soln11_02.cpp @@ -0,0 +1,42 @@ +// Exercise 11.2 Using a function with a reference parameter in the Integer class +/*********************************************************** + Using the version of compare()with the pass-by-value parameter, + the copy constructor is called because a copy of the argument + is passed to the function. + Using the version with the reference parameter a reference + to the object is passed to the function so no constructor call + is necessary. + You cannot overload a function with a reference parameter with + a function that has a non-reference parameter because the + compiler cannot tell which function should be called in any + particular instance. + ***********************************************************/ +#include +#include "Integer.h" + +int main() +{ + std::cout << "Create i with the value 10." << std::endl; + Integer i {10}; + i.show(); + std::cout << "Change value of i to 15." << std::endl; + i.setValue(15); + i.show(); + + std::cout << "Create j from object i." << std::endl; + Integer j {i}; + j.show(); + std::cout << "Set value of j to 150 times that of i." << std::endl; + j.setValue(150*i.getValue()); + j.show(); + + std::cout << "Create k with the value 789." << std::endl; + Integer k {789}; + k.show(); + std::cout << "Set value of k to sum of i and j values." << std::endl; + k.setValue(i.getValue()+j.getValue()); + k.show(); + + std::cout << "Result of comparing i and j is " << i.compare(j) << std::endl; + std::cout << "Result of comparing k and j is " << k.compare(j) << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 11/Soln11_03/Integer.cpp b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_03/Integer.cpp new file mode 100644 index 0000000..5271561 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_03/Integer.cpp @@ -0,0 +1,60 @@ +// Exercise 11.3 Integer.cpp +#include +#include "Integer.h" +using std::endl; + +// Copy constructor +Integer::Integer(Integer& obj) : n(obj.n) +{ + std::cout << "Object created by copy constructor." << std::endl; +} + +// Constructor +Integer::Integer(int m) : n(m) +{ + std::cout << "Object created." << std::endl; +} + +Integer* Integer::add(const Integer& obj) +{ + n += obj.n; + return this; +} + +Integer* Integer::subtract(const Integer& obj) +{ + n -= obj.n; + return this; +} + +Integer* Integer::multiply(const Integer& obj) +{ + n *= obj.n; + return this; +} + +void Integer::show() { + std::cout << "Value is " << n << std::endl; +} + +// Compare function +/* +int Integer::compare(const Integer obj) const { + if(n < obj.n) + return -1; + else if(n==obj.n) + return 0; + return 1; +} +*/ + +// Compare function with reference parameter +// /* +int Integer::compare(const Integer& obj) const { + if(n < obj.n) + return -1; + else if(n==obj.n) + return 0; + return 1; +} +// */ \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 11/Soln11_03/Integer.h b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_03/Integer.h new file mode 100644 index 0000000..3a66c6e --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_03/Integer.h @@ -0,0 +1,26 @@ +// Exercise 11.3 Integer.h +#ifndef INTEGER_H +#define INTEGER_H +class Integer +{ +private: + int n; + +public: + Integer(int m = 0); + Integer(Integer& obj); // Copy constructor +// int compare(const Integer obj) const; // Compare function + int compare(const Integer& obj) const; // Compare function with reference paramter + int getValue() {return n;} + void setValue(int m){ n = m; } + void show(); + + Integer* add(const Integer& obj); + Integer* add(int m); + Integer* subtract(const Integer& obj); + Integer* subtract(int m); + Integer* multiply(const Integer& obj); + Integer* multiply(int m); + +}; +#endif \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 11/Soln11_03/Soln11_03.cpp b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_03/Soln11_03.cpp new file mode 100644 index 0000000..31e78ce --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_03/Soln11_03.cpp @@ -0,0 +1,30 @@ +// Exercise 11.3 Implementing add(), subtract() and multiply() +/*********************************************************** + By returning the this pointer in the functions we can call + the functions successively in a single statement. Note the + parameter is a const reference - const because the argument + is not changed by the function and a reference to avoid + the overhead of copying objects. + The only other requirement for achieving the calculation + in a single statement is figuring out how to sequence to + operations to allow this. + ***********************************************************/ +#include +#include "Integer.h" + +int main() +{ + Integer a {4}; + Integer b {6}; + Integer c {7}; + Integer d {8}; + Integer x {5}; + + // We can calculate 4*5*5*5+6*5*5+7*5+8 as: + // ((4*5+6)*5+7)*5+8 + Integer result {a}; // Set result object as copy of a + Integer* pResult = &result; + std::cout << "Result is " + << pResult->multiply(x)->add(b)->multiply(x)->add(c)->multiply(x)->add(d)->getValue() + << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 11/Soln11_04/Integer.cpp b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_04/Integer.cpp new file mode 100644 index 0000000..40d73d3 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_04/Integer.cpp @@ -0,0 +1,21 @@ +// Exercise 11.4 Integer.cpp + +#include +#include "Integer.h" + +// Copy constructor +Integer::Integer(Integer& obj) : n(obj.n) +{ + std::cout << "Object created by copy constructor." << std::endl; +} + +// Constructor +Integer::Integer(int m) : n(m) +{ + std::cout << "Object created." << std::endl; +} + +void Integer::show() +{ + std::cout << "Value is " << n << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 11/Soln11_04/Integer.h b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_04/Integer.h new file mode 100644 index 0000000..bab6319 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_04/Integer.h @@ -0,0 +1,19 @@ +// Exercise 11.4 Integer.h + +#ifndef INTEGER_H +#define INTEGER_H + +class Integer +{ +private: + int n; + +public: + Integer(int m = 0); + Integer(Integer& obj); // Copy constructor + friend int compare(const Integer& obj1, const Integer& obj2); // friend compare function + int getValue() {return n;} + void setValue(int m){ n = m; } + void show(); +}; +#endif \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 11/Soln11_04/Soln11_04.cpp b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_04/Soln11_04.cpp new file mode 100644 index 0000000..1a90af4 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_04/Soln11_04.cpp @@ -0,0 +1,46 @@ +// Exercise 11.4 Using a friend function +/*********************************************************** + Implementing compare()as a friend is quite simple. We must + declare the function as a friend in the class definition. + We now need both objects as arguments and the code in the + body of the function just compares the n members of the arguments. + Both parameters are const references. + ***********************************************************/ +#include +#include "Integer.h" + +int main() +{ + std::cout << "Create i with the value 10." << std::endl; + Integer i {10}; + i.show(); + std::cout << "Change value of i to 15." << std::endl; + i.setValue(15); + i.show(); + + std::cout << "Create j from object i." << std::endl; + Integer j {i}; + j.show(); + std::cout << "Set value of j to 150 times that of i." << std::endl; + j.setValue(150*i.getValue()); + j.show(); + + std::cout << "Create k with the value 789." << std::endl; + Integer k {789}; + k.show(); + std::cout << "Set value of k to sum of i and j values." << std::endl; + k.setValue(i.getValue()+j.getValue()); + k.show(); + + std::cout << "Result of comparing i and j is " << compare(i, j) << std::endl; + std::cout << "Result of comparing k and j is " << compare(k, j) << std::endl; +} + +int compare(const Integer& obj1, const Integer& obj2) +{ + if(obj1.n < obj2.n) + return -1; + else if(obj1.n==obj2.n) + return 0; + return 1; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 11/Soln11_05/Box.cpp b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_05/Box.cpp new file mode 100644 index 0000000..e8a9c43 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_05/Box.cpp @@ -0,0 +1,18 @@ +// Box.cpp +#include +#include "Box.h" + +size_t Box::objectCount {}; // Initialize static member of Box class to 0 + +// Constructor definition +Box::Box(double lv, double wv, double hv) : length {lv}, width {wv}, height {hv} +{ + ++objectCount; + std::cout << "Box constructor 1 called." << std::endl; +} + +// Function to calculate the volume of a box +double Box::volume() const +{ + return length*width*height; +} diff --git a/9781484200087_Exercise_Solutions/Chapter 11/Soln11_05/Box.h b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_05/Box.h new file mode 100644 index 0000000..4b51bfc --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_05/Box.h @@ -0,0 +1,44 @@ +// Box.h +#ifndef BOX_H +#define BOX_H +#include +#include + +class Box +{ +private: + double length {1.0}; + double width {1.0}; + double height {1.0}; + +public: + // Constructors + Box(double lv, double wv, double hv) : + length {lv}, width {wv}, height {hv} {}; + + Box() {} // No-arg constructor + + Box(const Box& box) // Copy constructor + : length {box.length}, width {box.width}, height {box.height} + { } + + double volume() const // Volume of a box + { + return length*width*height; + } + + int compare(const Box& box) + { + if (volume() < box.volume()) return -1; + if (volume() == box.volume()) return 0; + return 1; + } + + void listBox() + { + std::cout << " Box(" << std::setw(2) << length << "," + << std::setw(2) << width << "," + << std::setw(2) << height << ")"; + } +}; +#endif diff --git a/9781484200087_Exercise_Solutions/Chapter 11/Soln11_05/Package.h b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_05/Package.h new file mode 100644 index 0000000..3af2d7e --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_05/Package.h @@ -0,0 +1,33 @@ +// Package.h +#ifndef PACKAGE_H +#define PACKAGE_H +#include +#include "Box.h" +template using ptr = std::shared_ptr; + +class Package +{ +private: + ptr pBox; // Pointer to the Box object + ptr pNext; // Pointer to the next Package + ptr pPrevious; // Pointer to the previous Package + +public: + Package(ptr pb) : pBox {pb}, pNext {}, pPrevious {} {} // Constructor + + + ptr& getBox() { return pBox; } // Retrieve the Box pointer + ptr& getNext() { return pNext; } // Get next Package address + ptr& getPrevious() { return pPrevious; } // Get next Package address + + void setNext(ptr& pPackage) // Point to next object + { + pNext = pPackage; + } + + void setPrevious(ptr& pPackage) // Point to previous object + { + pPrevious = pPackage; + } +}; +#endif diff --git a/9781484200087_Exercise_Solutions/Chapter 11/Soln11_05/Soln11_05.cpp b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_05/Soln11_05.cpp new file mode 100644 index 0000000..b0563d2 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_05/Soln11_05.cpp @@ -0,0 +1,76 @@ +// Exercise 11.5 +/* + The pPrevious data member in the Package class is a smart pointer to the previous object. + The Package class also has getPrevious() and setPrevious() members added. + The Truckload class has getLastBox() and getPreviousBox() members to support operation in reverse sequence + You could allow listing the Box objects in reverse sequence by adding a new function member. + I chose to implement the capability through a bool argument to listBoxes(). + The default parameter value of true allows listBoxes() to be called with no argument, + which ensures that the previous usage still works. +*/ + +#include +#include +#include +#include // For random number generator +#include // For time function +#include "Box.h" +#include "Truckload.h" + +// Function to generate a random integer 1 to count +inline size_t random(size_t count) +{ + return 1 + static_cast (count*static_cast(std::rand()) / (RAND_MAX + 1.0)); +} + +int main() +{ + const size_t dimLimit {99}; // Upper limit on Box dimensions + std::srand((unsigned)std::time(0)); // Initialize the random number generator + + Truckload load1; // Create an empty list + + // Add 12 random Box objects to the list + const size_t boxCount {12}; + for (size_t i {}; i < boxCount; ++i) + load1.addBox(std::make_shared(random(dimLimit), random(dimLimit), random(dimLimit))); + + std::cout << "The first list - forwards:\n"; + load1.listBoxes(); + std::cout << "The first list - in reverse:\n"; + load1.listBoxes(false); + + // Find the largest Box in the list + ptr pBox {load1.getFirstBox()}; + ptr pNextBox {}; + while (pNextBox = load1.getNextBox()) // Assign & then test pointer to next Box + if (pBox->compare(*pNextBox) < 0) + pBox = pNextBox; + + std::cout << "\nThe largest box in the first list is: "; + pBox->listBox(); + std::cout << std::endl; + load1.deleteBox(pBox); + std::cout << "\nAfter deleting the largest box, the list contains:\n"; + load1.listBoxes(); + + const size_t nBoxes {20}; // Number of vector elements + std::vector< ptr > boxes; // Array of Box objects + + for (size_t i {}; i < nBoxes; ++i) + boxes.push_back(std::make_shared(random(dimLimit), random(dimLimit), random(dimLimit))); + + Truckload load2(boxes); + std::cout << "\nThe second list - in reverse:\n"; + load2.listBoxes(); + + // Search backwards for smallest box + pBox = load2.getLastBox(); + while (pNextBox = load2.getPreviousBox()) + if (pBox->compare(*pNextBox) > 0) + pBox = pNextBox; + + std::cout << "\nThe smallest box in the second list is"; + pBox->listBox(); + std::cout << std::endl; +} diff --git a/9781484200087_Exercise_Solutions/Chapter 11/Soln11_05/Truckload.cpp b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_05/Truckload.cpp new file mode 100644 index 0000000..ee537e4 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_05/Truckload.cpp @@ -0,0 +1,134 @@ +#include // For smart pointers +#include // For vector +#include "Box.h" +#include "Package.h" +#include "Truckload.h" + +// Constructor +Truckload::Truckload(const std::vector< ptr >& boxes) +{ + for (auto pBox : boxes) + { + addBox(pBox); + } +} + +// Add a Box to the list +void Truckload::addBox(ptr pBox) +{ + auto pPackage = std::make_shared(pBox); // Create a Package + + if (pHead) // Check list is not empty + { + pTail->setNext(pPackage); // Add the new object to the tail + pPackage->setPrevious(pTail); + } + else // List is empty + { + pHead = pPackage; // so new object is the head + } + + pTail = pPackage; // Store its address as tail +} + +// Find the Package containing pBox and delete it from the list +bool Truckload::deleteBox(ptr pBox) +{ + pCurrent = pHead; // Start at the first box + ptr pPrevious; // Stores pointer to previous package + while (pCurrent) + { + if (pCurrent->getBox() == pBox) // Check for identical Box pointers + { // We found the box! + pPrevious = pCurrent->getPrevious(); + if (pPrevious) // If there's a previous box... + { + pPrevious->setNext(pCurrent->getNext()); // ...set its next to be the box after current + } + else // It is the first box... + { + pHead = pHead->getNext(); // ..so make the next the first box + } + pCurrent = nullptr; + return true; + } + pPrevious = pCurrent; // Make current the previous box... + pCurrent = pCurrent->getNext(); // ... and the next one current + } + return false; +} + +// Output all Box objects in the list +void Truckload::listBoxes(bool forward) +{ + size_t count {}; + if (forward) + { + pCurrent = pHead; + while (pCurrent) + { + pCurrent->getBox()->listBox(); + pCurrent = pCurrent->getNext(); + if(! (++count % 5)) std::cout << std::endl; + } + } + else + { + pCurrent = pTail; + while (pCurrent) + { + pCurrent->getBox()->listBox(); + pCurrent = pCurrent->getPrevious(); + if (!(++count % 5)) std::cout << std::endl; + } + + } + if (count % 5) std::cout << std::endl; +} + +// Get the first Box +ptr Truckload::getFirstBox() +{ + pCurrent = pHead->getNext(); + return pHead->getBox(); +} + +// Get the last Box +ptr Truckload::getLastBox() +{ + pCurrent = pTail->getPrevious(); + return pTail->getBox(); +} + +// Get the next Box +ptr Truckload::getNextBox() +{ + if (!pCurrent) // If there's no current... + return getFirstBox(); // ...return the 1st + + auto pPackage = pCurrent->getNext(); // Save the next package + if (pPackage) // If there is one... + { + pCurrent = pPackage; // Update current to the next + return pPackage->getBox(); + } + pCurrent = nullptr; // If we get to here... + return nullptr; // ...there was no next +} + +// Get the previous Box +ptr Truckload::getPreviousBox() +{ + if (!pCurrent) // If there's no current... + return getLastBox(); // ...return the last + + auto pPackage = pCurrent->getPrevious(); // Save the previous package + if (pPackage) // If there is one... + { + pCurrent = pPackage; // Update current to the previous + return pPackage->getBox(); + } + pCurrent = nullptr; // If we get to here... + return nullptr; // ...there was no previous +} + diff --git a/9781484200087_Exercise_Solutions/Chapter 11/Soln11_05/Truckload.h b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_05/Truckload.h new file mode 100644 index 0000000..b7854c9 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 11/Soln11_05/Truckload.h @@ -0,0 +1,35 @@ +// Truckload.h +#ifndef TRUCKLOAD_H +#define TRUCKLOAD_H + +#include +#include +#include "Package.h" + +class Truckload +{ +private: + ptr pHead; // First in the list + ptr pTail; // Last in the list + ptr pCurrent; // Last retrieved from the list + +public: + Truckload() {} // No-arg constructor empty truckload + + Truckload(ptr pBox) // Constructor - one Box + { + pHead = pTail = std::make_shared(pBox); + } + + Truckload(const std::vector< ptr >& boxes); // Constructor - vector of Boxes + + ptr getFirstBox(); // Get the first Box + ptr getLastBox(); // Get the last Box + ptr getNextBox(); // Get the next Box + ptr getPreviousBox(); // Get the previous Box + void addBox(ptr pBox); // Add a new Box + bool deleteBox(ptr pBox); // Delete a Box + void listBoxes(bool forward=true); // Output the Boxes - false for backwards +}; +#endif + diff --git a/9781484200087_Exercise_Solutions/Chapter 12/Soln12_01/Box.h b/9781484200087_Exercise_Solutions/Chapter 12/Soln12_01/Box.h new file mode 100644 index 0000000..c92d4a3 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 12/Soln12_01/Box.h @@ -0,0 +1,82 @@ +// Box.h +#ifndef BOX_H +#define BOX_H +#include +#include + +class Box +{ +private: + double length {1.0}; + double width {1.0}; + double height {1.0}; + +public: + // Constructors + Box(double lv, double wv, double hv) : length {lv}, width {wv}, height {hv} {} + + Box() {} // No-arg constructor + + Box(const Box& box) // Copy constructor + : length {box.length}, width {box.width}, height {box.height} {} + + double volume() const // Function to calculate the volume + { + return length*width*height; + } + + // Accessors + double getLength() const { return length; } + double getWidth() const { return width; } + double getHeight() const { return height; } + + bool operator<(const Box& aBox) const; // Less-than operator + bool operator<(double aValue) const; // Compare Box volume < double value + Box operator+(const Box& aBox) const; // Function to add two Box objects + Box operator*(size_t n) const; // Post-multiply an object by an integer + + friend std::ostream& operator<<(std::ostream& stream, const Box& box); +}; + +// Post-multiply an object by an integer +inline Box Box::operator*(size_t n) const +{ + return Box {length, width, n*height}; +} + +// Less-than comparison for Box objects +inline bool Box::operator<(const Box& aBox) const +{ + return volume() < aBox.volume(); +} + +// Compare the volume of a Box object with a constant +inline bool Box::operator<(double aValue) const +{ + return volume() < aValue; +} + +// Function comparing a constant with volume of a Box object +inline bool operator<(double aValue, const Box& aBox) +{ + return aValue < aBox.volume(); +} + +// Operator function to add two Box objects +inline Box Box::operator+(const Box& aBox) const +{ + // New object has larger length and width, and sum of heights + return Box {length > aBox.length ? length : aBox.length, + width > aBox.width ? width : aBox.width, + height + aBox.height}; +} + +inline std::ostream& operator<<(std::ostream& stream, const Box& box) +{ + stream << " Box(" << std::setw(2) << box.length << "," + << std::setw(2) << box.width << "," + << std::setw(2) << box.height << ")"; + return stream; +} + +#endif diff --git a/9781484200087_Exercise_Solutions/Chapter 12/Soln12_01/Soln12_01.cpp b/9781484200087_Exercise_Solutions/Chapter 12/Soln12_01/Soln12_01.cpp new file mode 100644 index 0000000..6cb63d2 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 12/Soln12_01/Soln12_01.cpp @@ -0,0 +1,15 @@ +// Ex12.1 +// Implementing the * operator for the Box class +// to post-multiply by an integer +#include +#include "Box.h" + + +int main() +{ + Box box {2, 3, 4}; + std::cout << "Box is " << box << std::endl; + size_t n {3}; + Box newBox = box*n; + std::cout << "After multiplying by " << n << " box is " << newBox << std::endl; +} diff --git a/9781484200087_Exercise_Solutions/Chapter 12/Soln12_02/Box.h b/9781484200087_Exercise_Solutions/Chapter 12/Soln12_02/Box.h new file mode 100644 index 0000000..307fb82 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 12/Soln12_02/Box.h @@ -0,0 +1,89 @@ +// Box.h +#ifndef BOX_H +#define BOX_H +#include +#include + +class Box +{ +private: + double length {1.0}; + double width {1.0}; + double height {1.0}; + +public: + // Constructors + Box(double lv, double wv, double hv) : length {lv}, width {wv}, height {hv} {} + + Box() {} // No-arg constructor + + Box(const Box& box) // Copy constructor + : length {box.length}, width {box.width}, height {box.height} {} + + double volume() const // Function to calculate the volume + { + return length*width*height; + } + + // Accessors + double getLength() const { return length; } + double getWidth() const { return width; } + double getHeight() const { return height; } + + bool operator<(const Box& aBox) const; // Less-than operator + bool operator<(double aValue) const; // Compare Box volume < double value + Box operator+(const Box& aBox) const; // Function to add two Box objects + Box operator*(size_t n) const; // Post-multiply an object by an integer + + friend std::ostream& operator<<(std::ostream& stream, const Box& box); +}; + +// Pre-multiply an object by an integer +inline Box operator*(size_t n, Box& box) +{ + return Box {box.getLength(), box.getWidth(), n*box.getHeight()}; +} + +// Post-multiply an object by an integer +inline Box Box::operator*(size_t n) const +{ + return Box {length, width, n*height}; +} + +// Less-than comparison for Box objects +inline bool Box::operator<(const Box& aBox) const +{ + return volume() < aBox.volume(); +} + +// Compare the volume of a Box object with a constant +inline bool Box::operator<(double aValue) const +{ + return volume() < aValue; +} + +// Function comparing a constant with volume of a Box object +inline bool operator<(double aValue, const Box& aBox) +{ + return aValue < aBox.volume(); +} + +// Operator function to add two Box objects +inline Box Box::operator+(const Box& aBox) const +{ + // New object has larger length and width, and sum of heights + return Box {length > aBox.length ? length : aBox.length, + width > aBox.width ? width : aBox.width, + height + aBox.height}; +} + + +inline std::ostream& operator<<(std::ostream& stream, const Box& box) +{ + stream << " Box(" << std::setw(2) << box.length << "," + << std::setw(2) << box.width << "," + << std::setw(2) << box.height << ")"; + return stream; +} + +#endif diff --git a/9781484200087_Exercise_Solutions/Chapter 12/Soln12_02/Soln12_02.cpp b/9781484200087_Exercise_Solutions/Chapter 12/Soln12_02/Soln12_02.cpp new file mode 100644 index 0000000..c7eeff4 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 12/Soln12_02/Soln12_02.cpp @@ -0,0 +1,14 @@ +// Ex12.2 +// Implementing the * operator for the Box class +// to pre-multiply by an integer +#include +#include "Box.h" + +int main() +{ + Box box {2, 3, 4}; + std::cout << "Box is " << box << std::endl; + size_t n {3}; + Box newBox = n*box; + std::cout << "After pre-multiplying by " << n << " box is " << newBox << std::endl; +} diff --git a/9781484200087_Exercise_Solutions/Chapter 12/Soln12_03/Box.h b/9781484200087_Exercise_Solutions/Chapter 12/Soln12_03/Box.h new file mode 100644 index 0000000..23909c0 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 12/Soln12_03/Box.h @@ -0,0 +1,120 @@ +// Box.h +#ifndef BOX_H +#define BOX_H +#include +#include + +class Box +{ +private: + double length {1.0}; + double width {1.0}; + double height {1.0}; + +public: + // Constructors + Box(double lv, double wv, double hv) : length {lv}, width {wv}, height {hv} {} + + Box() {} // No-arg constructor + + Box(const Box& box) // Copy constructor + : length {box.length}, width {box.width}, height {box.height} {} + + double volume() const // Function to calculate the volume + { + return length*width*height; + } + + // Accessors + double getLength() const { return length; } + double getWidth() const { return width; } + double getHeight() const { return height; } + + bool operator<(const Box& aBox) const; // Less-than operator + bool operator<(double aValue) const; // Compare Box volume < double value + Box operator+(const Box& aBox) const; // Function to add two Box objects + Box operator*(size_t n) const; // Post-multiply an object by an integer + size_t operator/(const Box& aBox) const; // Function to divide one Box object by another + + friend std::ostream& operator<<(std::ostream& stream, const Box& box); +}; + +// Function to divide one Box object by another - box1/box2 +// This assumes box2 boxes are in the same orientation when packed in box1 +// although box2 can be in any aorientation with respect to box1. +// The result will be zero if any dimension of box1 is less than that of box2. +inline size_t Box::operator/(const Box& box) const +{ + // Lambda expression to calculate division for a given orientation of box + auto trial = [this](double L, double W, double H){ return static_cast(this->length / L)* + static_cast(this->width / W)* + static_cast(this->height / H); }; + + size_t result {trial(box.length, box.width, box.height)}; // box in LxWxH orientation + if (!result) return 0; + + size_t temp {trial(box.length, box.height, box.width)}; // box in LxHxW orientation + if (temp > result)result = temp; + + temp = trial(box.width, box.height, box.length); // box in WxHxL orientation + if (temp > result)result = temp; + + temp = trial(box.width, box.length, box.height); // box in WxLxH orientation + if (temp > result)result = temp; + + temp = trial(box.height, box.length, box.width); // box in HxLxW orientation + if (temp > result)result = temp; + + temp = trial(box.height, box.width, box.length); // box in HxWxL orientation + if (temp > result)result = temp; + return result; +} + +// Pre-multiply an object by an integer +inline Box operator*(size_t n, Box& box) +{ + return Box {box.getLength(), box.getWidth(), n*box.getHeight()}; +} + +// Post-multiply an object by an integer +inline Box Box::operator*(size_t n) const +{ + return Box {length, width, n*height}; +} + +// Less-than comparison for Box objects +inline bool Box::operator<(const Box& aBox) const +{ + return volume() < aBox.volume(); +} + +// Compare the volume of a Box object with a constant +inline bool Box::operator<(double aValue) const +{ + return volume() < aValue; +} + +// Function comparing a constant with volume of a Box object +inline bool operator<(double aValue, const Box& aBox) +{ + return aValue < aBox.volume(); +} + +// Operator function to add two Box objects +inline Box Box::operator+(const Box& aBox) const +{ + // New object has larger length and width, and sum of heights + return Box {length > aBox.length ? length : aBox.length, + width > aBox.width ? width : aBox.width, + height + aBox.height}; +} + +inline std::ostream& operator<<(std::ostream& stream, const Box& box) +{ + stream << " Box(" << std::setw(2) << box.length << "," + << std::setw(2) << box.width << "," + << std::setw(2) << box.height << ")"; + return stream; +} + +#endif diff --git a/9781484200087_Exercise_Solutions/Chapter 12/Soln12_03/Soln12_03.cpp b/9781484200087_Exercise_Solutions/Chapter 12/Soln12_03/Soln12_03.cpp new file mode 100644 index 0000000..bbef95d --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 12/Soln12_03/Soln12_03.cpp @@ -0,0 +1,20 @@ +// Ex12.3 +// Implementing the / operator for the Box class +// to allow one Box object to be divides into another. +#include +#include "Box.h" + +int main() +{ + Box box1 {12, 5, 12}; + Box box2 {3, 4, 5}; + Box box3 {3, 4, 7}; + std::cout << "box1 is " << box1 << std::endl; + std::cout << "box2 is " << box2 << std::endl; + std::cout << "box3 is " << box3 << std::endl; + std::cout << "box1/box2 is " << box1 / box2 << std::endl; + std::cout << "box2/box3 is " << box2 / box3 << std::endl; + std::cout << "box1/box3 is " << box1 / box3 << std::endl; + std::cout << "(box1+2*box2)/box3 is " << (box1 + 2 * box2) / box3 << std::endl; +} + diff --git a/9781484200087_Exercise_Solutions/Chapter 12/Soln12_04/Box.h b/9781484200087_Exercise_Solutions/Chapter 12/Soln12_04/Box.h new file mode 100644 index 0000000..ba4a5f9 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 12/Soln12_04/Box.h @@ -0,0 +1,128 @@ +// Box.h +#ifndef BOX_H +#define BOX_H +#include +#include + +class Box +{ +private: + double length {1.0}; + double width {1.0}; + double height {1.0}; + +public: + // Constructors + Box(double lv, double wv, double hv) : length {lv}, width {wv}, height {hv} {} + + Box() {} // No-arg constructor + + Box(const Box& box) // Copy constructor + : length {box.length}, width {box.width}, height {box.height} {} + + double volume() const // Function to calculate the volume + { + return length*width*height; + } + + // Accessors + double getLength() const { return length; } + double getWidth() const { return width; } + double getHeight() const { return height; } + + bool operator<(const Box& aBox) const; // Less-than operator + bool operator<(double aValue) const; // Compare Box volume < double value + Box operator+(const Box& aBox) const; // Function to add two Box objects + Box operator*(size_t n) const; // Post-multiply an object by an integer + size_t operator/(const Box& aBox) const; // Function to divide one Box object by another + double operator%(const Box& aBox) const; // Volume left after dividing one Box object by another + + friend std::ostream& operator<<(std::ostream& stream, const Box& box); +}; + +// Volume left after dividing one Box object by another +// This is easy now we have the / operator +inline double Box::operator%(const Box& box) const +{ + size_t n {*this / box}; + return volume() - n*box.volume(); +} + +// Function to divide one Box object by another - box1/box2 +// This assumes box2 boxes are in the same orientation when packed in box1 +// although box2 can be in any aorientation with respect to box1. +// The result will be zero if any dimension of box1 is less than that of box2. +inline size_t Box::operator/(const Box& box) const +{ + // Lambda expression to calculate division for a given orientation of box + auto trial = [this](double L, double W, double H){ return static_cast(this->length / L)* + static_cast(this->width / W)* + static_cast(this->height / H); }; + + size_t result {trial(box.length, box.width, box.height)}; // box in LxWxH orientation + if (!result) return 0; + + size_t temp {trial(box.length, box.height, box.width)}; // box in LxHxW orientation + if (temp > result)result = temp; + + temp = trial(box.width, box.height, box.length); // box in WxHxL orientation + if (temp > result)result = temp; + + temp = trial(box.width, box.length, box.height); // box in WxLxH orientation + if (temp > result)result = temp; + + temp = trial(box.height, box.length, box.width); // box in HxLxW orientation + if (temp > result)result = temp; + + temp = trial(box.height, box.width, box.length); // box in HxWxL orientation + if (temp > result)result = temp; + return result; +} + +// Pre-multiply an object by an integer +inline Box operator*(size_t n, Box& box) +{ + return Box {box.getLength(), box.getWidth(), n*box.getHeight()}; +} + +// Post-multiply an object by an integer +inline Box Box::operator*(size_t n) const +{ + return Box {length, width, n*height}; +} + +// Less-than comparison for Box objects +inline bool Box::operator<(const Box& aBox) const +{ + return volume() < aBox.volume(); +} + +// Compare the volume of a Box object with a constant +inline bool Box::operator<(double aValue) const +{ + return volume() < aValue; +} + +// Function comparing a constant with volume of a Box object +inline bool operator<(double aValue, const Box& aBox) +{ + return aValue < aBox.volume(); +} + +// Operator function to add two Box objects +inline Box Box::operator+(const Box& aBox) const +{ + // New object has larger length and width, and sum of heights + return Box {length > aBox.length ? length : aBox.length, + width > aBox.width ? width : aBox.width, + height + aBox.height}; +} + +inline std::ostream& operator<<(std::ostream& stream, const Box& box) +{ + stream << " Box(" << std::setw(2) << box.length << "," + << std::setw(2) << box.width << "," + << std::setw(2) << box.height << ")"; + return stream; +} +#endif diff --git a/9781484200087_Exercise_Solutions/Chapter 12/Soln12_04/Soln12_04.cpp b/9781484200087_Exercise_Solutions/Chapter 12/Soln12_04/Soln12_04.cpp new file mode 100644 index 0000000..f189937 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 12/Soln12_04/Soln12_04.cpp @@ -0,0 +1,27 @@ +// Ex12.4 +// Implementing the % operator for the Box class +// to produce the volume left after dividing one Box object into another. +// This corresponds to the unoccupied space when the maximum number of smaller boxes +// are packed into the larger box. +#include +#include "Box.h" + +int main() +{ + Box box1 {12, 5, 12}; + Box box2 {3, 4, 5}; + Box box3 {5, 4, 5}; + std::cout << "box1 is " << box1 << std::endl; + std::cout << "box2 is " << box2 << std::endl; + std::cout << "Volume of box1 is " << box1.volume() << std::endl; + std::cout << "Volume of box2 is " << box2.volume() << std::endl; + + size_t n {box1 / box2}; + std::cout << "box1/box2 is " << n << std::endl; + std::cout << "With " << n << " of box2 in box1, the space left is " << box1%box2 << std::endl; + + n = box1 / box3; + std::cout << "box1/box3 is " << n << std::endl; + std::cout << "With " << n << " of box3 in box1, the space left is " << box1%box3 << std::endl; +} + diff --git a/9781484200087_Exercise_Solutions/Chapter 13/Soln13_01/Animal.cpp b/9781484200087_Exercise_Solutions/Chapter 13/Soln13_01/Animal.cpp new file mode 100644 index 0000000..4b70dc9 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 13/Soln13_01/Animal.cpp @@ -0,0 +1,16 @@ +// Exercise 13.1 - Animal.cpp +// Implementations of the Animal class and classes derived from Animal + +#include +#include +#include "Animal.h" +using std::string; + +// Constructor +Animal::Animal(string aName, int wt) : name(aName), weight(wt) {} + +// Identify the animal +void Animal::who() const +{ + std::cout << "My name is " << name << " and I weigh " << weight << "lbs." << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 13/Soln13_01/Animal.h b/9781484200087_Exercise_Solutions/Chapter 13/Soln13_01/Animal.h new file mode 100644 index 0000000..f7ce621 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 13/Soln13_01/Animal.h @@ -0,0 +1,32 @@ +// Exercise 13.1 - Animal.h +// Animal class and classes derived from Animal + +#ifndef ANIMAL_H +#define ANIMAL_H +#include +using std::string; + +class Animal +{ +private: + string name; // Name of the animal + int weight; // Weight of the animal + +public: + Animal(string aName, int wt); // Constructor + void who() const; // Display name and weight +}; + +class Lion: public Animal +{ +public: + Lion(string aName, int wt):Animal(aName, wt) {} +}; + +class Aardvark: public Animal +{ +public: + Aardvark(string aName, int wt):Animal(aName, wt){} +}; + +#endif \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 13/Soln13_01/Soln13_01.cpp b/9781484200087_Exercise_Solutions/Chapter 13/Soln13_01/Soln13_01.cpp new file mode 100644 index 0000000..ad4b1e0 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 13/Soln13_01/Soln13_01.cpp @@ -0,0 +1,10 @@ +// Exercise 13.1 Exercising the Animal classes +#include "Animal.h" + +int main() +{ + Lion myLion("Leo", 400); + Aardvark myAardvark("Algernon", 50); + myLion.who(); + myAardvark.who(); +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 13/Soln13_02/Animal.cpp b/9781484200087_Exercise_Solutions/Chapter 13/Soln13_02/Animal.cpp new file mode 100644 index 0000000..799630a --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 13/Soln13_02/Animal.cpp @@ -0,0 +1,30 @@ +// Exercise 15.2 - Animal.cpp +// Implementations of the Animal class and classes derived from Animal + +#include +#include +#include "Animal.h" +using std::string; + +// Constructor +Animal::Animal(string aName, int wt) : name(aName), weight(wt) {} + +// Identify the animal +void Animal::who() const +{ + std::cout << "My name is " << name << " and I weigh " << weight << "lbs." << std::endl; +} + +// Identify the Lion +void Lion::who() const +{ + std::cout << "\nI am a lion.\n"; + Animal::who(); // Call protected base function +} + +// Identify the Aardvark +void Aardvark::who() const +{ + std::cout << "\nI am an aardvark.\n"; + Animal::who(); // Call protected base function +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 13/Soln13_02/Animal.h b/9781484200087_Exercise_Solutions/Chapter 13/Soln13_02/Animal.h new file mode 100644 index 0000000..f507e80 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 13/Soln13_02/Animal.h @@ -0,0 +1,36 @@ +// Exercise 13.2 - Animal.h +// Animal class and classes derived from Animal + +#ifndef ANIMAL_H +#define ANIMAL_H +#include +using std::string; + +class Animal +{ +private: + string name; // Name of the animal + int weight; // Weight of the animal + +protected: + void who() const; // Display name and weight + +public: + Animal(string aName, int wt); // Constructor +}; + +class Lion: public Animal +{ +public: + Lion(string aName, int wt) : Animal(aName, wt) {} + void who() const; // Public member to access protected base function +}; + +class Aardvark: public Animal +{ +public: + Aardvark(string aName, int wt) : Animal(aName, wt) {} + void who() const; // Public member to access protected base function +}; + +#endif \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 13/Soln13_02/Soln13_02.cpp b/9781484200087_Exercise_Solutions/Chapter 13/Soln13_02/Soln13_02.cpp new file mode 100644 index 0000000..363d17f --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 13/Soln13_02/Soln13_02.cpp @@ -0,0 +1,12 @@ +// Exercise 13.2 The who() function for the base class has the protected access specifier, +// so we ensure the derived classes allow public access to the who() function. + +#include "Animal.h" + +int main() +{ + Lion myLion("Leo", 400); + Aardvark myAardvark("Algernon", 50); + myLion.who(); + myAardvark.who(); +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 13/Soln13_03/Animal.cpp b/9781484200087_Exercise_Solutions/Chapter 13/Soln13_03/Animal.cpp new file mode 100644 index 0000000..6716485 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 13/Soln13_03/Animal.cpp @@ -0,0 +1,27 @@ +// Exercise 13.3 - Animal.cpp +// Implementations of the Animal class and classes derived from Animal + +#include +#include +#include "Animal.h" +using std::string; + +// Constructor +Animal::Animal(string aName, int wt): name(aName), weight(wt) {} + +// Identify the animal +void Animal::who() const { + std::cout << "My name is " << name << " and I weigh " << weight << "lbs." << std::endl; +} + +// Identify the Lion +void Lion::who() const { + std::cout << "I am a lion.\n"; + Animal::who(); // Call base function +} + +// Identify the Aardvark +void Aardvark::who() const { + std::cout << "\nI am an aardvark.\n"; + Animal::who(); // Call base function +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 13/Soln13_03/Animal.h b/9781484200087_Exercise_Solutions/Chapter 13/Soln13_03/Animal.h new file mode 100644 index 0000000..b417984 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 13/Soln13_03/Animal.h @@ -0,0 +1,33 @@ +// Exercise 13.3 - Animal.h +// Animal class and classes derived from Animal + +#ifndef ANIMAL_H +#define ANIMAL_H +#include +using std::string; + +class Animal +{ +private: + string name; // Name of the animal + int weight; // Weight of the animal +public: + Animal(string aName, int wt); // Constructor + void who() const; // Display name and weight +}; + +class Lion: public Animal +{ +public: + Lion(string aName, int wt) : Animal(aName, wt) {} + void who() const; // Public member to access protected base function +}; + +class Aardvark: public Animal +{ +public: + Aardvark(string aName, int wt) : Animal(aName, wt){} + void who() const; // Public member to access protected base function +}; + +#endif \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 13/Soln13_03/Soln13_03.cpp b/9781484200087_Exercise_Solutions/Chapter 13/Soln13_03/Soln13_03.cpp new file mode 100644 index 0000000..285bdf4 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 13/Soln13_03/Soln13_03.cpp @@ -0,0 +1,18 @@ +// Exercise 13.3 By addng a few lines to the test program, we can see the difference +// between the calls to the base class and derived class who() functions. + +#include +#include "Animal.h" + +int main() +{ + Lion myLion("Leo", 400); + Aardvark myAardvark("Algernon", 50); + std::cout << "Calling derived versions of who():\n"; + myLion.who(); + myAardvark.who(); + + std::cout << "\nCalling base versions of who():\n"; + myLion.Animal::who(); + myAardvark.Animal::who(); +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 13/Soln13_04/Person.cpp b/9781484200087_Exercise_Solutions/Chapter 13/Soln13_04/Person.cpp new file mode 100644 index 0000000..755282c --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 13/Soln13_04/Person.cpp @@ -0,0 +1,32 @@ +// Exercise 13.4 Person.cpp +// Person class implementation + +#include "Person.h" +#include +using std::string; + +Person::Person(size_t theAge, string theName, char theGender) : age {theAge}, name {theName}, gender {theGender} +{ + // Instead of just initializing the members with the argument values, you could + // validate the arguments by doing reasonableness checks. + // e.g. Age should be less than 130 say. gender should be 'm' or 'f' + // To handle a failure sensibly we really need exceptions, but we don't get to those until chapter 15. +} + +// Display details of Person object +void Person::who() const +{ + std::cout << "\nThis is " << name << " who is " << age << " years old." << std::endl; +} + +// Display details of Employee object +void Employee::who() const +{ + std::cout << name << " is a " << (gender=='f'? "female": "male") << " employee aged " << age << "." << std::endl; +} + +// Display details of Executive object +void Executive::who() const +{ + std::cout << name << " is a " << (gender == 'f' ? "female" : "male") << " executive." << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 13/Soln13_04/Person.h b/9781484200087_Exercise_Solutions/Chapter 13/Soln13_04/Person.h new file mode 100644 index 0000000..ce9779c --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 13/Soln13_04/Person.h @@ -0,0 +1,43 @@ +// Exercise 13.4 Person.h +// Person class and classes derived from Person + +#ifndef PERSON_H +#define PERSON_H +#include +using std::string; + +class Person +{ +protected: + size_t age {}; // Age in years + string name; + char gender {'f'}; // 'm' or 'f' +public: + Person() = default; // Default constructor + Person(size_t theAge, string theName, char theGender); + void who() const; // Display details +}; + +class Employee : public Person +{ +protected: + long personnelNumber {}; + +public: + Employee() = default; // Default constructor - necessary to define arrays + Employee(size_t theAge, string theName, char theGender, long persNum) : + Person {theAge, theName, theGender}, personnelNumber {persNum} {} + void who() const; // Display details + +}; + +class Executive: public Employee +{ +public: + Executive() = default; // Default constructor - necessary to define arrays + Executive(size_t theAge, string theName, char theGender, long persNum) : + Employee {theAge, theName, theGender, persNum} {} + void who() const; // Display details +}; + +#endif \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 13/Soln13_04/Soln13_04.cpp b/9781484200087_Exercise_Solutions/Chapter 13/Soln13_04/Soln13_04.cpp new file mode 100644 index 0000000..8f9b20a --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 13/Soln13_04/Soln13_04.cpp @@ -0,0 +1,35 @@ +// Exercise 13.4 Working with Employee and Executive objects + +#include +#include +#include "Person.h" + +int main() +{ + std::vector employees { + Employee(21, "Randy Marathon", 'm', 34567), + Employee(32, "Anna Pothecary", 'f', 34578), + Employee(46, "Peter Out", 'm', 34589), + Employee(37, "Sheila Rangeit", 'f', 34598), + Employee(65, "Jack Ittin", 'm', 34667) + }; + + for(auto& employee : employees) + employee.who(); + + std::cout << std::endl; + + std::vector executives { + Executive(44, "Irwin Pootlemeyer", 'm', 35567), + Executive(32, "Alexa Workwell", 'f', 35578), + Executive(42, "Steve Stove", 'm', 35589), + Executive(33, "Sue Neenuf", 'f', 35598), + Executive(29, "Melanie Clair", 'f', 35667) + }; + + for (auto& executive : executives) + { + executive.who(); + executive.Employee::who(); + } +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 14/Soln14_01/Animals.cpp b/9781484200087_Exercise_Solutions/Chapter 14/Soln14_01/Animals.cpp new file mode 100644 index 0000000..e652ed7 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 14/Soln14_01/Animals.cpp @@ -0,0 +1,69 @@ +// Exercise 14.1 Animals.cpp +// Implementations of the Animal class and classes derived from Animal + +#include "Animals.h" +#include +#include +#include +using std::string; + +// Constructor +Animal::Animal(string theName, size_t wt) : name(theName), weight(wt) {} + +// Return string describing the animal +string Animal::who() const +{ + return string("My name is ") + name + ". My weight is " + std::to_string(weight) + " lbs."; +} + +// Return string describing the sheep +string Sheep::who() const +{ + return string("I am a sheep. ") + Animal::who(); // Call base function for common data +} + +// Make like a sheep +string Sheep::sound() const +{ + return string("Baaaa!!"); +} + +// Return string describing the dog +string Dog::who() const +{ + return string("I am a dog. ") + Animal::who(); // Call base function for common data +} + +// Make like a dog +string Dog::sound() const +{ + return string("Woof woof!!"); +} + +// Return string describing the cow +string Cow::who() const +{ + return string("I am a cow. ") + Animal::who(); // Call base function for common data +} + +// Make like a cow +string Cow::sound() const +{ + return string("Mooooo!!"); +} + +// Constructor from a vector of animals +Zoo::Zoo(std::vector& new_animals) : animals {new_animals} {} + +// Add an animal to the zoo +void Zoo::addAnimal(PAnimal animal) +{ + animals.push_back(animal); +} + +// Output the animals and the sound they make +void Zoo::showAnimals() +{ + for(auto animal : animals) + std::cout << animal->who() << ' ' << animal->sound() << std::endl; +} diff --git a/9781484200087_Exercise_Solutions/Chapter 14/Soln14_01/Animals.h b/9781484200087_Exercise_Solutions/Chapter 14/Soln14_01/Animals.h new file mode 100644 index 0000000..d16963b --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 14/Soln14_01/Animals.h @@ -0,0 +1,62 @@ +// Exercise 14.1 Animals.h +// Animal classes and class defining a Zoo +#ifndef ANIMALS_H +#define ANIMALS_H +#include +#include +#include +using std::string; +class Animal; // Class name declaration +using PAnimal = std::shared_ptr; // required to compile this alias + +class Animal +{ +private: + string name; // Name of the animal + size_t weight {}; // Weight of the animal + +public: + Animal(string theName, size_t wt); // Constructor + virtual string who() const; // Return string containing name and weight + virtual string sound() const = 0; // Display sound of an animal + +}; + +class Sheep: public Animal +{ +public: + Sheep(string theName, size_t wt) : Animal(theName, wt) {} + string who() const override; // Return string containing name and weight + string sound() const override; // Display sound of a sheep +}; + +class Dog: public Animal +{ +public: + Dog(string theName, size_t wt) : Animal(theName, wt) {} + string who() const override; // Return string containing name and weight + string sound() const override; // Display sound of a dog +}; + +class Cow : public Animal +{ +public: + Cow(string theName, size_t wt) : Animal(theName, wt) {} + string who() const override; // Return string containing name and weight + string sound() const override; // Return sound of a cow +}; + +// The Zoo class representing a collection of animals +class Zoo +{ +private: + std::vector animals; // Stores smart pointers to the animals + +public: + Zoo() = default; // Default constructor for an empty zoo + Zoo(std::vector& new_animals); // Constructor from a vector of animals + void addAnimal(PAnimal animal); // Add an animal to the zoo + void showAnimals(); // Output the animals and the sound they make +}; + +#endif \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 14/Soln14_01/Soln14_01.cpp b/9781484200087_Exercise_Solutions/Chapter 14/Soln14_01/Soln14_01.cpp new file mode 100644 index 0000000..b3f1803 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 14/Soln14_01/Soln14_01.cpp @@ -0,0 +1,60 @@ +// Exercise 14.1 Exercising Zoo and Animal classes +#include "Animals.h" +#include +#include +#include +#include +#include +using std::string; + +// Function to generate a random integer 0 to count-1 +int random(size_t count) +{ + return static_cast((count*static_cast(rand()))/(RAND_MAX+1L)); +} + +int main() +{ + std::srand((unsigned)std::time(0)); // Seed random number generator + + std::vector dogNames { "Fido", "Rover" , "Lassie" , "Lambikins", "Poochy", + "Spit", "Gnasher" , "Samuel" , "Wellington" , "Patch" }; + std::vector sheepNames { "Bozo", "Killer", "Tasty", "Woolly", "Chops", + "Blackie", "Whitey", "Eric" , "Sean" , "Shep" }; + std::vector cowNames { "Dolly", "Daisy", "Shakey", "Amy", "Dilly", + "Dizzy", "Eleanor", "Zippy" , "Zappy", "Happy" }; + + size_t minDogWt {1}; // Minimum weight of a dog in pounds + size_t maxDogWt {120}; // Maximum weight of a dog in pounds + size_t minSheepWt {80}; // Minimum weight of a dog in pounds + size_t maxSheepWt {150}; // Maximum weight of a dog in pounds + size_t minCowWt {800}; // Minimum weight of a dog in pounds + size_t maxCowWt {1500}; // Maximum weight of a dog in pounds + + std::vector animals; // Stores smart pointers to animals + size_t nAnimals {}; // Number of animals to be created + std::cout << "How many animals in the zoo? "; + std::cin >> nAnimals; + // Create random animals + for (size_t i {}; i < nAnimals; ++i) + switch(random(3)) + { + case 0: // Create a sheep + animals.push_back(std::make_shared(sheepNames[random(sheepNames.size())], minSheepWt + random(maxSheepWt-minSheepWt+1))); + break; + case 1: // Create a dog + animals.push_back(std::make_shared(dogNames[random(dogNames.size())], minDogWt+random(maxDogWt-minDogWt+1))); + break; + case 2: // Create a cow + animals.push_back(std::make_shared(cowNames[random(cowNames.size())], minCowWt+random(maxCowWt-minCowWt+1))); + break; + default: + std::cout << "\nInvalid animal type selection." << std::endl; + break; + } + + // Create a zoo containing the animals + // You could also create an empty zoo and add animals one at a time + Zoo theZoo(animals); + theZoo.showAnimals(); // Display the animals +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 14/Soln14_02/Lengths.cpp b/9781484200087_Exercise_Solutions/Chapter 14/Soln14_02/Lengths.cpp new file mode 100644 index 0000000..b196bd5 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 14/Soln14_02/Lengths.cpp @@ -0,0 +1,12 @@ +// Exercise 16.2 Lengths.cpp +// Length classes implementations + +#include "Lengths.h" + +// Initialize static data members +double BaseLength::mmPerInch {25.4}; +double BaseLength::mmPerMeter {1000.0}; +double BaseLength::inchesPerYard {36.0}; +double BaseLength::yardsPerPerch {5.5}; + + diff --git a/9781484200087_Exercise_Solutions/Chapter 14/Soln14_02/Lengths.h b/9781484200087_Exercise_Solutions/Chapter 14/Soln14_02/Lengths.h new file mode 100644 index 0000000..5d05153 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 14/Soln14_02/Lengths.h @@ -0,0 +1,72 @@ +// Exercise 14.2 Lengths.h +// Length classes +// You could define the static data members using constexpr if your compiler supports it. +// This would remove the need to initialize them outside the class. +#ifndef LENGTHS_H +#define LENGTHS_H + +class BaseLength +{ +protected: + long mm {}; + static double mmPerInch; + static double mmPerMeter; + static double inchesPerYard; + static double yardsPerPerch; + +public: + BaseLength() = default; // Default constructor + BaseLength(long n) : mm(n){} // Constructor from millimeters + virtual double length() const { return mm; }; // Return the length +}; + +// Classes representing specific units store their own unit values. +// Lengths are also stored in the base class member mm. +// You could store all engths as just millimeters but this +// would result in an error of up to 1 mm in the length displayed. +// This is because the conversion of a length to an integer rounds down +// and there could be further small errors from decimal/binary floating point conversions. +class Inches: public BaseLength +{ +protected: + double inches {}; + +public: + Inches() = default; + Inches(double ins) :BaseLength {static_cast(0.5 + mmPerInch*ins)}, inches {ins} {} + double length() const override { return inches; } // Return the length + }; + +class Meters: public BaseLength +{ +protected: + double meters {}; + +public: + Meters() = default; + Meters(double m) :BaseLength {static_cast(0.5 + mmPerMeter*m)}, meters {m} {} + double length() const override { return meters; } // Return the length +}; + +class Yards: public BaseLength +{ +protected: + double yards {}; + +public: + Yards() = default; + Yards(double yds) :BaseLength {static_cast(0.5 + inchesPerYard*mmPerInch*yds)}, yards {yds} {} + double length() const override { return yards; } // Return the length +}; + +class Perches: public BaseLength +{ +protected: + double perches {}; + +public: + Perches():BaseLength(){} + Perches(double pch) :BaseLength {static_cast(0.5 + yardsPerPerch*inchesPerYard*mmPerInch*pch)}, perches {pch} {} + double length() const override { return perches; } // Return the length +}; +#endif \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 14/Soln14_02/Soln14_02.cpp b/9781484200087_Exercise_Solutions/Chapter 14/Soln14_02/Soln14_02.cpp new file mode 100644 index 0000000..de49839 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 14/Soln14_02/Soln14_02.cpp @@ -0,0 +1,79 @@ +// Exercise 14.2 Creating length objects + +#include "Lengths.h" +#include +#include +#include +#include +#include +#include +using std::string; + +// Read a length from the keyboard +std::shared_ptr readLength() +{ + double value {}; // Stores the length value + string units; // Stores the units + + for(;;) + { + std::cout << "\nEnter a length: "; + std::cin >> std::skipws >> value; // Skip whitespace and read the value + if (!value) return nullptr; + + getline(std::cin, units); // Rest of line is units + size_t index {units.find_first_not_of(" ")}; // Find first non-blank in units + + // Return the object type corresponding to the units + switch(toupper(units[index])) + { + case 'M': + return std::make_shared(value); + case 'I': + return std::make_shared(value); + case 'Y': + return std::make_shared(value);; + case 'P': + return std::make_shared(value); + default: + std::cout << "\nInvalid units. Re-enter length: "; + break; + } + } +} + +int main() +{ + std::vector > pLengths; + std::cout << "\nYou can enter lengths in inches, meters, yards, or perches." + << "\nThe first character following the number specifies the units." + << "\nThis can be i, m, y, or p, for inches, meters, yards, or perches." + << "\ne.g. '22 ins' is 22 inches, '3.5 p' or '3.5perches' is 3.5 perches, '1y' is 1 yard." + << std::endl + << "\nPlease enter a length followed by the units or 0 to end:"; + + while (true) + { + auto p = readLength(); + if (!p)break; + + pLengths.push_back(p); + + } + + // Output the lengths - we must figure out what type they are to display the units + for(auto p : pLengths) + { + string units(" invalid type"); + if(typeid(*p)==typeid(Inches)) + units = " inches"; + else if(typeid(*p)==typeid(Meters)) + units = " meters"; + else if(typeid(*p)==typeid(Yards)) + units = " yards"; + else if(typeid(*p)==typeid(Perches)) + units = " perches"; + std::cout << "\nLength is " << std::fixed << std::setprecision(2) << p->length() << units + << " which is " << static_cast(p->BaseLength::length()) << " millimeters." << std::endl; + } +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 14/Soln14_03/Lengths.cpp b/9781484200087_Exercise_Solutions/Chapter 14/Soln14_03/Lengths.cpp new file mode 100644 index 0000000..88b4710 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 14/Soln14_03/Lengths.cpp @@ -0,0 +1,34 @@ +// Exercise 16.3 Lengths.cpp +// Length classes implementations + +#include "Lengths.h" + +// Initialize static data members +double BaseLength::mmPerInch {25.4}; +double BaseLength::mmPerMeter {1000.0}; +double BaseLength::inchesPerYard {36.0}; +double BaseLength::yardsPerPerch {5.5}; + +BaseLength::operator Inches()const +{ return Inches {mm / mmPerInch}; } // Conversion to Inches +BaseLength::operator Yards()const +{ return Yards {mm / (mmPerInch*inchesPerYard)}; } // Conversion to Yards +BaseLength::operator Meters()const +{ return Meters {mm / mmPerMeter}; } // Conversion to Meters +BaseLength::operator Perches()const +{ return Perches {mm / (mmPerInch*inchesPerYard*yardsPerPerch)}; } // Conversion to Perches + +Inches::operator Yards()const +{ return Yards {inches / inchesPerYard}; } // Conversion to Yards +Inches::operator Perches()const +{ return Perches {inches / (inchesPerYard*yardsPerPerch)}; } // Conversion to Perches + +Yards::operator Perches()const +{ return Perches {yards / yardsPerPerch}; } // Conversion to Perches +Yards::operator Inches()const +{ return Inches {yards * inchesPerYard}; } // Conversion to Inches + +Perches::operator Inches()const +{ return Inches {perches * yardsPerPerch*inchesPerYard}; } // Conversion to Perches +Perches::operator Yards()const +{ return Yards {perches * yardsPerPerch}; } // Conversion to Yards diff --git a/9781484200087_Exercise_Solutions/Chapter 14/Soln14_03/Lengths.h b/9781484200087_Exercise_Solutions/Chapter 14/Soln14_03/Lengths.h new file mode 100644 index 0000000..ef067e6 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 14/Soln14_03/Lengths.h @@ -0,0 +1,99 @@ +// Exercise 14.3 Lengths.h +// Length classes with conversion operator functions + +#ifndef LENGTHS_H +#define LENGTHS_H + + +// Class name declarations - we need these because we refer +// to the class names before they are defined. +class Inches; +class Yards; +class Meters; +class Perches; + +class BaseLength +{ +protected: + long mm {}; + static double mmPerInch; + static double mmPerMeter; + static double inchesPerYard; + static double yardsPerPerch; + +public: + BaseLength() = default; // Default constructor + BaseLength(long n) : mm(n) {} // Constructor from millimeters + virtual double length() const { return mm; }; // Return the length + + virtual operator Inches()const; // Conversion to Inches + virtual operator Yards()const; // Conversion to Yards + virtual operator Meters()const; // Conversion to Meters + virtual operator Perches()const; // Conversion to Perches + }; + +// If the derived classes did not define overrides for conversion to the same type +// the inherited conversion would be called which . +// would result in an error in the length displayed for the current type. +class Inches : public BaseLength +{ +protected: + double inches {}; + +public: + Inches() = default; + Inches(double ins) :BaseLength {static_cast(0.5 + mmPerInch*ins)}, inches {ins} {} + double length() const override { return inches; } // Return the length + + // Inherited conversion to meters is OK + operator Inches() const override { return *this; } + operator Yards()const override; // Conversion to Yards + operator Perches()const override; // Conversion to Perches + + }; + +class Meters: public BaseLength +{ +protected: + double meters {}; + +public: + Meters() = default; + Meters(double m) :BaseLength {static_cast(0.5 + mmPerMeter*m)}, meters {m} {} + double length() const override { return meters; } // Return the length + + // All inherited conversion operator functions are OK +}; + +class Yards: public BaseLength +{ +protected: + double yards {}; + +public: + Yards() = default; + Yards(double yds) :BaseLength {static_cast(0.5 + inchesPerYard*mmPerInch*yds)}, yards {yds} {} + double length() const override { return yards; } // Return the length + + // Inherited conversion to meters is OK + operator Yards() const override { return *this; } + operator Perches()const override; // Conversion to Perches + operator Inches()const override; // Conversion to Inches +}; + +class Perches: public BaseLength +{ +protected: + double perches {}; + +public: + Perches():BaseLength(){} + Perches(double pch) :BaseLength {static_cast(0.5 + yardsPerPerch*inchesPerYard*mmPerInch*pch)}, perches {pch} {} + double length() const override { return perches; } // Return the length + + operator Perches() const override { return *this; } + operator Inches()const override; // Conversion to Perches + operator Yards()const override; // Conversion to Yards +}; + +#endif \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 14/Soln14_03/Soln14_03.cpp b/9781484200087_Exercise_Solutions/Chapter 14/Soln14_03/Soln14_03.cpp new file mode 100644 index 0000000..f0b688f --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 14/Soln14_03/Soln14_03.cpp @@ -0,0 +1,74 @@ +// Exercise 14.3 Converting length objects + +#include "Lengths.h" +#include +#include +#include +#include +#include +#include +using std::string; + +// Read a length from the keyboard +std::shared_ptr readLength() +{ + double value {}; // Stores the length value + string units; // Stores the units + + for(;;) + { + std::cout << "\nEnter a length: "; + std::cin >> std::skipws >> value; // Skip whitespace and read the value + if (!value) return nullptr; + + getline(std::cin, units); // Rest of line is units + size_t index {units.find_first_not_of(" ")}; // Find first non-blank in units + + // Return the object type corresponding to the units + switch(toupper(units[index])) + { + case 'M': + return std::make_shared(value); + case 'I': + return std::make_shared(value); + case 'Y': + return std::make_shared(value);; + case 'P': + return std::make_shared(value); + default: + std::cout << "\nInvalid units. Re-enter length: "; + break; + } + } +} + +int main() +{ + std::vector > pLengths; + std::cout << "\nYou can enter lengths in inches, meters, yards, or perches." + << "\nThe first character following the number specifies the units." + << "\nThis can be i, m, y, or p, for inches, meters, yards, or perches." + << "\ne.g. '22 ins' is 22 inches, '3.5 p' or '3.5perches' is 3.5 perches, '1y' is 1 yard." + << std::endl + << "\nPlease enter a length followed by the units or 0 to end:"; + + while (true) + { + auto p = readLength(); + if (!p)break; + + pLengths.push_back(p); + + } + + // Output the lengths - we don't need to figure out what type they are to + // display the units - we just use the operator onversion functions + for(auto p : pLengths) + { + std::cout << "\nLength is " << static_cast(*p).length() << std::fixed << std::setprecision(2) << " inches, " + << static_cast(*p).length() << " yards, " + << static_cast(*p).length() << " meters, " + << static_cast(*p).length() << " perches, " + << static_cast(p->BaseLength::length()) << " millimeters." << std::endl; + } +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 14/Soln14_04/Lengths.cpp b/9781484200087_Exercise_Solutions/Chapter 14/Soln14_04/Lengths.cpp new file mode 100644 index 0000000..7d1d0a2 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 14/Soln14_04/Lengths.cpp @@ -0,0 +1,54 @@ +// Exercise 16.3 Lengths.cpp +// Length classes implementations + +#include "Lengths.h" + +// Initialize static data members +double BaseLength::mmPerInch {25.4}; +double BaseLength::mmPerMeter {1000.0}; +double BaseLength::inchesPerYard {36.0}; +double BaseLength::yardsPerPerch {5.5}; + +BaseLength::operator Inches()const +{ + return Inches {mm / mmPerInch}; +} // Conversion to Inches +BaseLength::operator Yards()const +{ + return Yards {mm / (mmPerInch*inchesPerYard)}; +} // Conversion to Yards +BaseLength::operator Meters()const +{ + return Meters {mm / mmPerMeter}; +} // Conversion to Meters +BaseLength::operator Perches()const +{ + return Perches {mm / (mmPerInch*inchesPerYard*yardsPerPerch)}; +} // Conversion to Perches + +Inches::operator Yards()const +{ + return Yards {inches / inchesPerYard}; +} // Conversion to Yards +Inches::operator Perches()const +{ + return Perches {inches / (inchesPerYard*yardsPerPerch)}; +} // Conversion to Perches + +Yards::operator Perches()const +{ + return Perches {yards / yardsPerPerch}; +} // Conversion to Perches +Yards::operator Inches()const +{ + return Inches {yards * inchesPerYard}; +} // Conversion to Inches + +Perches::operator Inches()const +{ + return Inches {perches * yardsPerPerch*inchesPerYard}; +} // Conversion to Perches +Perches::operator Yards()const +{ + return Yards {perches * yardsPerPerch}; +} // Conversion to Yards diff --git a/9781484200087_Exercise_Solutions/Chapter 14/Soln14_04/Lengths.h b/9781484200087_Exercise_Solutions/Chapter 14/Soln14_04/Lengths.h new file mode 100644 index 0000000..c88a771 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 14/Soln14_04/Lengths.h @@ -0,0 +1,180 @@ +// Exercise 14.3 Lengths.h +// Length classes with conversion operator functions + +#ifndef LENGTHS_H +#define LENGTHS_H +#include + + +// Class name declarations - we need these because we refer +// to the class names before they are defined. +class Inches; +class Yards; +class Meters; +class Perches; + +class BaseLength +{ +protected: + long mm {}; + static double mmPerInch; + static double mmPerMeter; + static double inchesPerYard; + static double yardsPerPerch; + +public: + BaseLength() = default; // Default constructor + BaseLength(long n) : mm(n) {} // Constructor from millimeters + virtual double length() const { return mm; }; // Return the length + + virtual operator Inches()const; // Conversion to Inches + virtual operator Yards()const; // Conversion to Yards + virtual operator Meters()const; // Conversion to Meters + virtual operator Perches()const; // Conversion to Perches + }; + +// If the derived classes did not define overrides for conversion to the same type +// the inherited conversion would be called which . +// would result in an error in the length displayed for the current type. +class Inches : public BaseLength +{ +protected: + double inches {}; + +public: + Inches() = default; + Inches(double ins) :BaseLength {static_cast(0.5 + mmPerInch*ins)}, inches {ins} {} + double length() const override { return inches; } // Return the length + + // Inherited conversion to meters is OK + operator Inches() const override { return *this; } + operator Yards()const override; // Conversion to Yards + operator Perches()const override; // Conversion to Perches + + // Constructors for conversions + Inches(Meters& m); + Inches(Yards& yds); + Inches(Perches& p); + }; + +class Meters: public BaseLength +{ +protected: + double meters {}; + +public: + Meters() = default; + Meters(double m) : BaseLength {static_cast(0.5 + mmPerMeter*m)}, meters {m} {} + double length() const override { return meters; } // Return the length + + // Constructors for conversions + Meters(Inches& ins); + Meters(Yards& yds); + Meters(Perches& p); +}; + +class Yards: public BaseLength +{ +protected: + double yards {}; + +public: + Yards() = default; + Yards(double yds) :BaseLength {static_cast(0.5 + inchesPerYard*mmPerInch*yds)}, yards {yds} {} + double length() const override { return yards; } // Return the length + + // Inherited conversion to meters is OK + operator Yards() const override { return *this; } + operator Perches()const override; // Conversion to Perches + operator Inches()const override; // Conversion to Inches + + // Constructors for conversions + Yards(Meters& m); + Yards(Inches& ins); + Yards(Perches& p); +}; + +class Perches: public BaseLength +{ +protected: + double perches {}; + +public: + Perches():BaseLength(){} + Perches(double pch) :BaseLength {static_cast(0.5 + yardsPerPerch*inchesPerYard*mmPerInch*pch)}, perches {pch} {} + double length() const override { return perches; } // Return the length + + operator Perches() const override { return *this; } + operator Inches()const override; // Conversion to Perches + operator Yards()const override; // Conversion to Yards + + // Constructors for conversions + Perches(Meters& m); + Perches(Inches& ins); + Perches(Yards& yds); +}; + +// Constructors for conversions +inline Perches::Perches(Meters& m) : Perches {m.length()*mmPerMeter / (mmPerInch*inchesPerYard*yardsPerPerch)} +{ +// std::cout << "Perches constructor from Meters" << std::endl; +} + +inline Perches::Perches(Inches& ins) : Perches {ins.length() / (inchesPerYard*yardsPerPerch)} +{ +// std::cout << "Perches constructor from Inches" << std::endl; +} + +inline Perches::Perches(Yards& yds) : Perches {yds.length() / yardsPerPerch} +{ +// std::cout << "Perches constructor from Yards" << std::endl; +} + +inline Yards::Yards(Meters& m) : Yards {m.length()*mmPerMeter / (mmPerInch*inchesPerYard)} +{ +// std::cout << "Yards constructor from Meters" << std::endl; +} + +inline Yards::Yards(Inches& ins) : Yards {ins.length() / inchesPerYard} +{ + std::cout << "Yards constructor from Inches" << std::endl; +} + +inline Yards::Yards(Perches& p) : Yards {p.length()*yardsPerPerch} +{ +// std::cout << "Yards constructor from Perches" << std::endl; +} + +inline Meters::Meters(Inches& ins) : Meters {ins.length()*mmPerInch / mmPerMeter} +{ +// std::cout << "Meters constructor from Inches" << std::endl; +} + +inline Meters::Meters(Yards& yds) : Meters {yds.length()*inchesPerYard*mmPerInch / mmPerMeter} +{ +// std::cout << "Meters constructor from Yards" << std::endl; +} + +inline Meters::Meters(Perches& p) : Meters {p.length()*yardsPerPerch*inchesPerYard*mmPerInch / mmPerMeter} +{ +// std::cout << "Meters constructor from Perches" << std::endl; +} + + +inline Inches::Inches(Meters& m) : Inches {m.length()*mmPerMeter / mmPerInch} +{ +// std::cout << "Inches constructor from Meters" << std::endl; +} + +inline Inches::Inches(Yards& yds) : Inches {yds.length()*inchesPerYard} +{ +// std::cout << "Inches constructor from Yards" << std::endl; +} + +inline Inches::Inches(Perches& p) : Inches {p.length()*yardsPerPerch*inchesPerYard} +{ +// std::cout << "Inches constructor from Perches" << std::endl; +} + + +#endif \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 14/Soln14_04/Soln14_04.cpp b/9781484200087_Exercise_Solutions/Chapter 14/Soln14_04/Soln14_04.cpp new file mode 100644 index 0000000..38a3399 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 14/Soln14_04/Soln14_04.cpp @@ -0,0 +1,105 @@ +// Exercise 14.4 Constructors for converting length objects + +#include "Lengths.h" +#include +#include +#include +#include +#include +#include +using std::string; + +// Read a length from the keyboard +std::shared_ptr readLength() +{ + double value {}; // Stores the length value + string units; // Stores the units + + for(;;) + { + std::cout << "\nEnter a length: "; + std::cin >> std::skipws >> value; // Skip whitespace and read the value + if (!value) return nullptr; + + getline(std::cin, units); // Rest of line is units + size_t index {units.find_first_not_of(" ")}; // Find first non-blank in units + + // Return the object type corresponding to the units + switch(toupper(units[index])) + { + case 'M': + return std::make_shared(value); + case 'I': + return std::make_shared(value); + case 'Y': + return std::make_shared(value);; + case 'P': + return std::make_shared(value); + default: + std::cout << "\nInvalid units. Re-enter length: "; + break; + } + } +} + +int main() +{ + std::vector > pLengths; + std::cout << "\nYou can enter lengths in inches, meters, yards, or perches." + << "\nThe first character following the number specifies the units." + << "\nThis can be i, m, y, or p, for inches, meters, yards, or perches." + << "\ne.g. '22 ins' is 22 inches, '3.5 p' or '3.5perches' is 3.5 perches, '1y' is 1 yard." + << std::endl + << "\nPlease enter a length followed by the units or 0 to end:"; + + while (true) + { + auto p = readLength(); + if (!p)break; + + pLengths.push_back(p); + + } + + // Output the lengths + // These conversion can only use the conversion operators, because they are polymorphic + // (because a pLengths element is a smart pointer to the base class type and points to a derived class object). + for (auto p : pLengths) + { + std::cout << "\nLength is " << static_cast(*p).length() << std::fixed << std::setprecision(2) << " inches, " + << static_cast(*p).length() << " yards, " + << static_cast(*p).length() << " meters, " + << static_cast(*p).length() << " perches, " + << static_cast(p->BaseLength::length()) << " millimeters." << std::endl; + } + + // Objects to exercise constructors to do conversions + Inches inLength {5}; + Yards ydLength {5}; + Meters mLength {5}; + Perches pchLength {5}; + + // The following use the class constructors to do conversions. You can verify this + // by uncommenting the output statement to each constructor. + // However, if you comment out the conversion constructors for any of the classes, + // it should still work using the inherited conversion operators instead. + std::cout << "\nLength is " << inLength.length() << " inches, " + << static_cast(inLength).length() << " yards, " + << static_cast(inLength).length() << " meters, " + << static_cast(inLength).length() << " perches.\n"; + + std::cout << "Length is " << static_cast(ydLength).length() << " inches, " + << ydLength.length() << " yards, " + << static_cast(ydLength).length() << " meters, " + << static_cast(ydLength).length() << " perches,\n"; + + std::cout << "Length is " << static_cast(mLength).length() << " inches, " + << static_cast(mLength).length() << " yards, " + << mLength.length() << " meters, " + << static_cast(mLength).length() << " perches.\n"; + + std::cout << "Length is " << static_cast(pchLength).length() << " inches, " + << static_cast(pchLength).length() << " yards, " + << static_cast(pchLength).length() << " meters, " + << pchLength.length() << " perches. " << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 15/Soln15_01/CurveBall.cpp b/9781484200087_Exercise_Solutions/Chapter 15/Soln15_01/CurveBall.cpp new file mode 100644 index 0000000..791aae6 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 15/Soln15_01/CurveBall.cpp @@ -0,0 +1,9 @@ +// Exercise 15.1 CurveBall.cpp +// Implementation of CurveBall exception class + +#include "CurveBall.h" + +const char* CurveBall::what() const +{ + return "CurveBall exception"; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 15/Soln15_01/CurveBall.h b/9781484200087_Exercise_Solutions/Chapter 15/Soln15_01/CurveBall.h new file mode 100644 index 0000000..eeefd0f --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 15/Soln15_01/CurveBall.h @@ -0,0 +1,13 @@ +// Exercise 15.1 CurveBall.h +// Definition of CurveBall Exception class + +#ifndef CURVEBALL_H +#define CURVEBALL_H +#include + +class CurveBall: public std::exception +{ +public: + const char* what() const; +}; +#endif //CURVEBALL_H \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 15/Soln15_01/Soln15_01.cpp b/9781484200087_Exercise_Solutions/Chapter 15/Soln15_01/Soln15_01.cpp new file mode 100644 index 0000000..1a67371 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 15/Soln15_01/Soln15_01.cpp @@ -0,0 +1,37 @@ +// Exercise 15.1 Throwing and catching CurveBalls +#include "CurveBall.h" +#include +#include +#include + +// Function to generate a random integer 0 to count-1 +size_t random(size_t count) +{ + return static_cast((count*static_cast(rand()))/(RAND_MAX+1UL)); +} + +// Throw a CurveBall exception 25% of the time +void sometimes() +{ + CurveBall e; + if(random(20)<5) + throw e; +} + +int main() +{ + std::srand((unsigned)std::time(0)); // Seed random number generator + size_t number {1000}; // Number of loop iterations + size_t exceptionCount {}; // Count of exceptions thrown + + for (size_t i {}; i < number; ++i) + try + { + sometimes(); + } + catch(CurveBall& e) + { + exceptionCount++; + } + std::cout << "CurveBall exception thrown " << exceptionCount << " times out of " << number << ".\n"; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 15/Soln15_02/CurveBall.cpp b/9781484200087_Exercise_Solutions/Chapter 15/Soln15_02/CurveBall.cpp new file mode 100644 index 0000000..42e5aeb --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 15/Soln15_02/CurveBall.cpp @@ -0,0 +1,14 @@ +// Exercise 15.2 CurveBall.cpp +// Implementation of CurveBall and TooManyExceptions exception classes + +#include "CurveBall.h" + +const char* CurveBall::what() const +{ + return "CurveBall exception"; +} + +const char* TooManyExceptions::what() const +{ + return "TooManyExceptions exception"; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 15/Soln15_02/CurveBall.h b/9781484200087_Exercise_Solutions/Chapter 15/Soln15_02/CurveBall.h new file mode 100644 index 0000000..b615f45 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 15/Soln15_02/CurveBall.h @@ -0,0 +1,20 @@ +// Exercise 15.2 CurveBall.h +// Definition of CurveBall and TooManyExceptions exception classes + +#ifndef CURVEBALL_H +#define CURVEBALL_H +#include + +class CurveBall: public std::exception +{ + public: + const char* what() const; +}; + +class TooManyExceptions: public std::exception +{ + public: + const char* what() const; +}; + +#endif //CURVEBALL_H \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 15/Soln15_02/Soln15_02.cpp b/9781484200087_Exercise_Solutions/Chapter 15/Soln15_02/Soln15_02.cpp new file mode 100644 index 0000000..6525a09 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 15/Soln15_02/Soln15_02.cpp @@ -0,0 +1,39 @@ +// Exercise 15.2 Throwing and catching CurveBalls and throwing TooManyExceptions +#include "CurveBall.h" +#include +#include +#include + +// Function to generate a random integer 0 to count-1 +size_t random(size_t count) +{ + return static_cast((count*static_cast(rand())) / (RAND_MAX + 1UL)); +} + +// Throw a CurveBall exception 25% of the time +void sometimes(){ + CurveBall e; + if(random(20)<5) + throw e; +} + +// This program will terminate abnormally when the TooManyExceptions exception is thrown. +int main() +{ + std::srand((unsigned)std::time(0)); // Seed random number generator + size_t number {1000}; // Number of loop iterations + size_t exceptionCount {}; // Count of exceptions thrown + TooManyExceptions eTooMany; // Exception object + + for (size_t i {}; i < number; ++i) + try + { + sometimes(); + } + catch(CurveBall& e) + { + std::cout << e.what() << std::endl; + if(++exceptionCount > 10) + throw eTooMany; + } +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 15/Soln15_03/CurveBall.cpp b/9781484200087_Exercise_Solutions/Chapter 15/Soln15_03/CurveBall.cpp new file mode 100644 index 0000000..e595336 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 15/Soln15_03/CurveBall.cpp @@ -0,0 +1,14 @@ +// Exercise 15.3 CurveBall.cpp +// Implementation of CurveBall and TooManyExceptions exception classes + +#include "CurveBall.h" + +const char* CurveBall::what() const +{ + return "CurveBall exception"; +} + +const char* TooManyExceptions::what() const +{ + return "TooManyExceptions exception"; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 15/Soln15_03/CurveBall.h b/9781484200087_Exercise_Solutions/Chapter 15/Soln15_03/CurveBall.h new file mode 100644 index 0000000..f0ef34b --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 15/Soln15_03/CurveBall.h @@ -0,0 +1,20 @@ +// Exercise 15.3 CurveBall.h +// Definition of CurveBall and TooManyExceptions exception classes + +#ifndef CURVEBALL_H +#define CURVEBALL_H +#include + +class CurveBall : public std::exception +{ +public: + const char* what() const; +}; + +class TooManyExceptions : public std::exception +{ +public: + const char* what() const; +}; + +#endif //CURVEBALL_H \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 15/Soln15_03/Soln15_03.cpp b/9781484200087_Exercise_Solutions/Chapter 15/Soln15_03/Soln15_03.cpp new file mode 100644 index 0000000..4e5984a --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 15/Soln15_03/Soln15_03.cpp @@ -0,0 +1,52 @@ +// Exercise 15.3 Implementing a terminate handler +// All we have to do is add the definition for our terminate handler function +// and set our terminate handler in place of the default in main() +// The class definitions are as for Ex 15.2 +#include "CurveBall.h" +#include +#include +#include + +// Terminate handler +void myHandler() +{ + std::cout << "My termination handler called." << std::endl; + exit(1); +} + +// Function to generate a random integer 0 to count-1 +size_t random(size_t count) +{ + return static_cast((count*static_cast(rand())) / (RAND_MAX + 1UL)); +} + +// Throw a CurveBall exception 25% of the time +void sometimes() +{ + CurveBall e; + if (random(20)<5) + throw e; +} + +// This program will be terminated by the myHandler() function when the TooManyExceptions exception is thrown. +int main() +{ + std::srand((unsigned)std::time(0)); // Seed random number generator + size_t number {1000}; // Number of loop iterations + size_t exceptionCount {}; // Count of exceptions thrown + TooManyExceptions eTooMany; // Exception object + + set_terminate(myHandler); // Install our own handler + + for (size_t i {}; i < number; ++i) + try + { + sometimes(); + } + catch (CurveBall& e) + { + std::cout << e.what() << std::endl; + if (++exceptionCount > 10) + throw eTooMany; + } +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 15/Soln15_04/Soln15_04.cpp b/9781484200087_Exercise_Solutions/Chapter 15/Soln15_04/Soln15_04.cpp new file mode 100644 index 0000000..c3ce36f --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 15/Soln15_04/Soln15_04.cpp @@ -0,0 +1,57 @@ +// Exercise 15.4 Exercising the SparseArray class +/* +This is trickier than it looks. Throwing exceptions is the easy bit. +The hard bit is defining SparseArray to allow operations on elements to work as you would expect. +An important part of this is the operator double() member of the inner Element class. +This allows the compiler to insert implicit casts when required, which allows arithmetic operations +between SparseArray elements. +Note that operator[]() for the SparseArray class returns an object of type SparseArray::Element. +This is necessary to allow new values to be assigned to an element. +The compiler can convert this object to its value whenever it is required by the context. +*/ +#include "SparseArray.h" +#include +#include + +int main() +{ + SparseArray values {50}; // Create a sparse array with capacity for 50 + + // Exercise subscripting + try + { + values[10] = 20; + values[15] = 30; + values[21] = 40; + values[32] = 25; + values[44] = 22; + values[1] = values[10] + values[15]; + values[16] = values[15] + 1; + values[17] = 2 + values[16]; + values[2] = values[21] + values[32]; + values[5] = values[1] + values[2] + values[44]; + std::cout << "values[2] = " << values[2] << std::endl; + std::cout << "values[10] = " << values[10] << std::endl; + std::cout << "Product of values[2] and values[10] is " << values[2] * values[10] << std::endl; + values.show(); + values[14] = values[60]; // Causes an exception to be thrown - out of range index + } + catch(std::exception& e) + { + std::cout << "Exception caught: " << e.what() << std::endl; + } + + // Exercise the copy constructor and assignment operator + try + { + SparseArray copies {values}; + copies.show(); + copies[0] = values[5]; + values = copies; + values.show(); + } + catch(std::exception& e) + { + std::cout << "Exception caught: " << e.what() << std::endl; + } +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 15/Soln15_04/SparseArray.cpp b/9781484200087_Exercise_Solutions/Chapter 15/Soln15_04/SparseArray.cpp new file mode 100644 index 0000000..1495c79 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 15/Soln15_04/SparseArray.cpp @@ -0,0 +1,127 @@ +// Exercise 15.4 SparseArray.cpp +// Implementation of the SparseArray class + +#include "SparseArray.h" +#include +#include +#include +#include +#include + +// Copy constructor +SparseArray::SparseArray(const SparseArray& array) +{ + maxElements = array.maxElements; // Copy max element count + + if(array.pFirst) // If there is a first element... + { + pLast = pFirst = std::make_shared(*array.pFirst); // ...duplicate it + + PElement pTemp; + PElement pCurrent = array.pFirst; + while(pCurrent = pCurrent->pNext) // Duplicate any further elements + { + pTemp = pLast; // Save the address of the last + pLast = std::make_shared(*pCurrent); // Make the new one the last + pTemp->pNext = pLast; // Set the next pointer of old last + pLast->pPrevious = pTemp; // Set previous pointer of new last + } + } + else + pLast = pFirst = nullptr; +} + + +// Assignment operator +SparseArray& SparseArray::operator=(const SparseArray& array) +{ + if(this == &array) // Check for rhs same as lhs + return *this; + + maxElements = array.maxElements; + PElement pCurrent; + if(array.pFirst) + { + pLast = pFirst = std::make_shared(*array.pFirst); + PElement pTemp; + pCurrent = array.pFirst; + while(pCurrent = pCurrent->pNext) + { + pTemp = pLast; + pLast = std::make_shared(*pCurrent); + pTemp->pNext = pLast; + pLast->pPrevious = pTemp; + pTemp = pLast; + } + } + else + pLast = pFirst = nullptr; + return *this; +} + +// Subscript operator for non-const objects +SparseArray::Element& SparseArray::operator[](size_t index) +{ + if(index >= maxElements) + { // Out of range index + string message {"Invalid index in SparseArray: "}; + message = message + std::to_string(index) + "\nIndex limits are 0 to " + std::to_string(maxElements - 1); + throw std::out_of_range(message); + } + + // Search the list for a Element corresponding to index + PElement pCurrent = pFirst; + while(pCurrent) + { + if(pCurrent->index == index) + return *pCurrent; + if(pCurrent->index > index) + break; + pCurrent = pCurrent->pNext; + } + + // If we get to here, the element doesn't exist + // so we must create one + PElement pElement = std::make_shared(index); + if(pCurrent) + { // It's not the end of the list so we must insert the element + if(pCurrent->pPrevious) + { // Current has a previous Element so just insert the new Element between the two + pCurrent->pPrevious->pNext = pElement; + pElement->pPrevious = pCurrent->pPrevious; + pCurrent->pPrevious = pElement; + pElement->pNext = pCurrent; + } + else + { // Current must be the first so add new Element as first + pElement->pNext = pCurrent; + pCurrent->pPrevious = pElement; + pFirst = pElement; + } + } + else + { // We are at the end of the list so we must append the new element + if(pLast) + { // This is a last element so add it after that + pLast->pNext = pElement; + pElement->pPrevious = pLast; + pLast = pElement; + } + else + pFirst = pLast = pElement; // The list was empty + } + return *pElement; // Return the new element +} + +// Display the elements of a SparseArray +void SparseArray::show() +{ + PElement pCurrent = pFirst; + while(pCurrent) + { + std::cout << "\n[" << std::setw(2) << pCurrent->index << "] = " + << std::fixed << std::setprecision(2) << pCurrent->value; + pCurrent = pCurrent->pNext; + } + std::cout << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 15/Soln15_04/SparseArray.h b/9781484200087_Exercise_Solutions/Chapter 15/Soln15_04/SparseArray.h new file mode 100644 index 0000000..91293ff --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 15/Soln15_04/SparseArray.h @@ -0,0 +1,58 @@ +// Exercise 15.4 SparseArray.h +// SparseArray class definition - stores pointers to strings + +#ifndef SPARSEARRAY_H +#define SPARSEARRAY_H +#include +#include +using std::string; + +class SparseArray +{ +// Local using declarations - in scope of SparseArray class +class Element; +using PElement = std::shared_ptr; +private: + PElement pFirst; // Pointer to first non-zero element element + PElement pLast; // Pointer to last non-zero element element + size_t maxElements {}; + +public: + SparseArray(size_t n) : maxElements {n} {} // Constructor + SparseArray(const SparseArray& array); // Copy constructor + SparseArray& operator=(const SparseArray& array); // Assignment operator + Element& operator[](size_t index); // Subscript SparseArray + void show(); // display array elements + +private: + // Element class definition + class Element + { + public: + size_t index {}; // Index of element + double value {}; // Element value + PElement pNext {}; // Pointer to next element + PElement pPrevious {}; // Pointer to previous element + + Element(size_t newIndex) : index(newIndex) {} // Constructor + Element(const Element& element) : index(element.index), value {element.value} {} // Copy constructor + + // Assign an Element to an Element + Element& operator= (Element& element) + { + value = element.value; + return *this; + } + + // Assign a value to an element + Element& operator= (double v) + { + value = v; + return *this; + } + + operator double() { return value; } + }; +}; + +#endif //SPARSEARRAY_H \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 16/Soln16_01/Soln16_01.cpp b/9781484200087_Exercise_Solutions/Chapter 16/Soln16_01/Soln16_01.cpp new file mode 100644 index 0000000..03a1e93 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 16/Soln16_01/Soln16_01.cpp @@ -0,0 +1,50 @@ +// Exercise 16.1 Exercising the SparseArray class template +// We create a sparse array of integers, populate 20 of its +// entries (checking for duplicates among the randomly generated indices) +// and output the resulting index/value pairs. + +// For practical use, the SparseArray template needs a mechanism for iteration over the elements that exist. +// Otherwise you could be executing a loop with several million iterations to access 10 elements with values. +// By now you should be able to see that this is not difficult to implement... + +#include "SparseArrayT.h" +#include +#include +#include +#include +using std::string; + + +// Function to generate a random integer 0 to count-1 +int random(size_t count) +{ + return static_cast((count*static_cast(rand()))/(RAND_MAX+1UL)); +} + +int main() +{ + SparseArray numbers; // Create sparse array + const size_t count {20}; // Number of elements to be created + size_t index {}; // Stores new index value + srand((unsigned)time(0)); // Seed random number generator + + try + { + for (size_t i {}; i < count; ++i) // Create count entries in numbers array + { + // Must ensure that indexes after the first are not duplicates + for(;;) + { + index = random(500); // Get a random index 0 to 499 + if (numbers.element_exists(index)) continue; + break; // We have a unique index + } + numbers[index] = 32+random(181); // Store value at new index position + } + } + catch(std::exception& e) + { + std::cout << "\nException thrown " << e.what() << std::endl; + } + numbers.show(); +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 16/Soln16_01/SparseArrayT.h b/9781484200087_Exercise_Solutions/Chapter 16/Soln16_01/SparseArrayT.h new file mode 100644 index 0000000..882ae2c --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 16/Soln16_01/SparseArrayT.h @@ -0,0 +1,170 @@ +// Exercise 16.1 SparseArrayT.h +// SparseArray class template definition +/* +The SparseArray template uses smart pointers to manage Node objects that are array elements. +This means a destructor is not required for SparseArray. +Raw pointers to objects are stored in the array and objects are copied in the free store +so the nested Node class needs a destructor. +If the sparse array could only store smart pointers, it could only be used for objects in the free store. +A raw pointer can pointer to either free store objects or automatic objects. +*/ + +#ifndef SPARSEARRAYT_H +#define SPARSEARRAYT_H +#include +#include +#include +#include +using std::string; + + +template class SparseArray +{ + class Node; + using PNode = std::shared_ptr < Node >; +private: + PNode pFirst; // Pointer to first element node + PNode pLast; // Pointer to last element node + +public: + SparseArray() = default; // Constructor + SparseArray(const SparseArray& array); // Copy constructor + SparseArray& operator=(const SparseArray& array); // Assignment operator + T& operator[](size_t index); // Subscript SparseArray + bool element_exists(size_t index); // Return true if element exists + void show(); // display array elements + +private: + // Node class definition + class Node + { + public: + size_t index {}; // Index of element + T* pObject; // Address of object + PNode pNext; // Pointer to next node + PNode pPrevious; // Pointer to previous node + + Node(size_t newIndex) : index(newIndex), pObject(new T) {} // Constructor + Node(const Node& node) : index(node.index), pObject(new T(*node.pObject)) {} // Copy constructor + ~Node(){ delete pObject; } // Destructor + }; +}; + + +// Copy constructor template +template SparseArray::SparseArray(const SparseArray& array) +{ + if (array.pFirst) + { // If there is a first element + pLast = pFirst = std::make_shared(*array.pFirst); // Duplicate it + + PNode pTemp; + PNode pCurrent {array.pFirst}; + while (pCurrent = pCurrent->pNext) + { // Duplicate any further nodes + pTemp = pLast; // Save the address of the last + pLast = std::make_shared(*pCurrent); // Make the new one the last + pTemp->pNext = pLast; // Set the next pointer of old last + pLast->pPrevious = pTemp; // Set previous pointer of new last + } + } +} + +// Assignment operator template +template SparseArray& SparseArray::operator=(const SparseArray& array) +{ + if (this == &array) // Check for rhs same as lhs + return *this; + + PNode pCurrent; + if (array.pFirst) + { + pLast = pFirst = std::make_shared(*array.pFirst); + Node* pTemp; + pCurrent = array.pFirst; + while (pCurrent = pCurrent->pNext) + { + pTemp = pLast; + pLast = std::make_shared(*pCurrent); + pTemp->pNext = pLast; + pLast->pPrevious = pTemp; + pTemp = pLast; + } + } + return *this; +} + +// Subscript operator for non-const objects +template T& SparseArray::operator[](size_t index) +{ + // Search the list for a node corresponding to index + PNode pCurrent {pFirst}; + while (pCurrent) + { + if (pCurrent->index == index) + return *pCurrent->pObject; + if (pCurrent->index > index) + break; + pCurrent = pCurrent->pNext; + } + + // If we get to here, the element doesn't exist + // so we must create one + PNode pNode = std::make_shared(index); + pNode->pObject = new T; + if (pCurrent) // If its not the end of the list we must insert the element + { + if (pCurrent->pPrevious) // If current has a previous node just insert the new node + { + pCurrent->pPrevious->pNext = pNode; + pNode->pPrevious = pCurrent->pPrevious; + pCurrent->pPrevious = pNode; + pNode->pNext = pCurrent; + } + else // Current must be the first so add new node as first + { + pNode->pNext = pCurrent; + pCurrent->pPrevious = pNode; + pFirst = pNode; + } + } + else + { // We must append the element + if (pLast) + { + pLast->pNext = pNode; + pNode->pPrevious = pLast; + pLast = pNode; + } + else + pFirst = pLast = pNode; + } + return *pNode->pObject; // Return the new element +} + +// Display the elements of a SparseArray +template void SparseArray::show() +{ + PNode pCurrent {pFirst}; + while (pCurrent) + { + std::cout << "\n[" << std::setw(2) << pCurrent->index << "] = " << *pCurrent->pObject; + pCurrent = pCurrent->pNext; + } + std::cout << std::endl; +} + +// Test for existence of element at index +template +bool SparseArray::element_exists(size_t index) +{ + PNode p {pFirst}; + while (p) + { + if (p->index == index) return true; + p = p->pNext; + } + return false; +} + +#endif //SPARSEARRAY_H \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 16/Soln16_02/LinkedListT.h b/9781484200087_Exercise_Solutions/Chapter 16/Soln16_02/LinkedListT.h new file mode 100644 index 0000000..f04c6f2 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 16/Soln16_02/LinkedListT.h @@ -0,0 +1,161 @@ +// Exercise 16.2 LinkedListT.h +/* +The LinkedList template uses smart pointers to manage Node objects. +This means a destructor is not required. +Raw pointers to objects are stored in the list and objects are copied in the free stored +so the nested Node class needs a destructor. +If the linked list could only store smart pointers, it could only be used for objects in the free store. +A raw pointer can pointer to either free store objects or automatic objects. +*/ +#ifndef LINKEDLISTT_H +#define LINKEDLISTT_H +#include + +template class LinkedList +{ + class Node; // Declaration required because class is not yet defined + using PNode = std::shared_ptr; // and we refeence it here +private: + PNode pHead {}; // Pointer to first element node + PNode pTail {}; // Pointer to last element node + PNode pLast {}; // Pointer to last node accessed + +public: + LinkedList() = default; // Constructor + LinkedList(const LinkedList& list); // Copy constructor + LinkedList& operator=(const LinkedList& list); // Assignment operator + void addHead(T* pObj); // Add an object to the head + void addTail(T* pObj); // Add an object to the tail + T* getHead(); // Get the object at the head + T* getTail(); // Get the object at the head + T* getNext(); // Get the next object + T* getPrevious(); // Get the previous object + +private: + // Node class definition + class Node + { + public: + size_t index {}; // Index of element + T* pObject {}; // Reference to object + PNode pNext {}; // Pointer to next node + PNode pPrevious {}; // Pointer to previous node + + Node(T* pObj) : pObject {new T {*pObj}} {} // Constructor + Node(const Node& node) : index {node.index}, pObject {new T {*node.pObject}} {} // Copy constructor + + ~Node() { delete pObject; } // Destructor + }; +}; + + +// Copy constructor template +template LinkedList::LinkedList(const LinkedList& list) +{ + if (list.pHead) + { // If there is a first element + pTail = pHead = std::make_shared(*list.pHead); // Duplicate it + + PNode pTemp; + PNode pCurrent = list.pHead; + while (pCurrent = pCurrent->pNext) + { // Duplicate any further nodes + pTemp = pTail; // Save the address of the last + pTail = std::make_shared(*pCurrent); // Make the new one the last + pTemp->pNext = pTail; // Set the next pointer of old last + pTail->pPrevious = pTemp; // Set previous pointer of new last + } + } +} + +// Assignment operator template +template LinkedList& LinkedList::operator=(const LinkedList& list) +{ + if (this == &list) // Check for rhs same as lhs + return *this; + + PNode pCurrent; + if (list.pHead) + { + pTail = pHead = std::make_shared(*list.pHead); + Node* pTemp {}; + pCurrent = list.pHead; + while (pCurrent = pCurrent->pNext) + { + pTemp = pTail; + pTail = std::make_shared(*pCurrent); + pTemp->pNext = pTail; + pTail->pPrevious = pTemp; + pTemp = pTail; + } + } + return *this; +} + +// Template function member to add an object to the head of the list +template void LinkedList::addHead(T* pObj) +{ + if (pHead) + { + pHead->pPrevious = std::make_shared(pObj); + pHead->pPrevious->pNext = pHead; + pHead = pHead->pPrevious; + } + else + pHead = pTail = std::make_shared(pObj); + pLast = pHead; +} + +// Template function member to add an object to the tail of the list +template void LinkedList::addTail(T* pObj) +{ + if (pTail) + { + pTail->pNext = std::make_shared(pObj); + pTail->pNext->pPrevious = pTail; + pTail = pTail->pNext; + } + else + pHead = pTail = std::make_shared(pObj); + pLast = pTail; +} + +// Template function member to get the object at the head of the list +template T* LinkedList::getHead() +{ + pLast = pHead; + if (pHead) + return pHead->pObject; + else + return nullptr; +} + +// Template function member to get the object at the tail of the list +template T* LinkedList::getTail() +{ + pLast = pTail; + if (pTail) + return pTail->pObject; + else + return nullptr; +} + +// Template function member to get the next object +template T* LinkedList::getNext() +{ + if (pLast) + if (pLast = pLast->pNext) + return pLast->pObject; + return nullptr; +} + +// Template function member to get the previous object +template T* LinkedList::getPrevious() +{ + if (pLast) + if (pLast = pLast->pPrevious) + return pLast->pObject; + return nullptr; +} + +#endif //LINKEDLISTT_H \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 16/Soln16_02/Soln16_02.cpp b/9781484200087_Exercise_Solutions/Chapter 16/Soln16_02/Soln16_02.cpp new file mode 100644 index 0000000..2c284c2 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 16/Soln16_02/Soln16_02.cpp @@ -0,0 +1,54 @@ +// Exercise 16.2 Exercising the LinkedList template class +// This program reverses the text that is entered +#include "LinkedListT.h" +#include +#include +using std::string; + +int main() +{ + string text; // Stores input prose or poem + std::cout << "\nEnter a poem or prose over one or more lines." + << "Terminate the input with #:\n"; + getline(std::cin, text, '#'); + + LinkedList words; // List to store words + + // Extract words and store in the list + string separators(" ,.\"?!;:\n"); // Separators between words + size_t start {}; // Start of a word + size_t end {}; // separator position after a word + while(string::npos != (start = text.find_first_not_of(separators, start))) + { + end = text.find_first_of(separators, start+1); + words.addTail(&text.substr(start,end-start)); + start = end; + } + + // List the words 5 to a line + std::cout << "\nThe words are:\n\n"; + auto pStr = words.getHead(); + size_t count {}; // Word counter + const size_t perline {5}; // Worde per line + while (pStr) + { + std::cout << *pStr << ' '; + if (!(++count % perline)) + std::cout << std::endl; + pStr = words.getNext(); + } + std::cout << std::endl; + + // List the words in reverse order 5 to a line + std::cout << "\nIn reverse order, the words are:\n\n"; + pStr = words.getTail(); + count = 0; + while(pStr) + { + std::cout << *pStr << ' '; + if(!(++count % perline)) + std::cout << std::endl; + pStr = words.getPrevious(); + } + std::cout << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 16/Soln16_03/LinkedListT.h b/9781484200087_Exercise_Solutions/Chapter 16/Soln16_03/LinkedListT.h new file mode 100644 index 0000000..40ab450 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 16/Soln16_03/LinkedListT.h @@ -0,0 +1,161 @@ +// Exercise 16.3 LinkedListT.h +/* +The LinkedList template uses smart pointers to manage Node objects. +This means a destructor is not required. +Raw pointers to objects are stored in the list and objects are copied in the free stored +so the nested Node class needs a destructor. +If the linked list could only store smart pointers, it could only be used for objects in the free store. +A raw pointer can pointer to either free store objects or automatic objects. +*/ +#ifndef LINKEDLISTT_H +#define LINKEDLISTT_H +#include + +template class LinkedList +{ + class Node; // Declaration required because class is not yet defined + using PNode = std::shared_ptr; +private: + PNode pHead {}; // Pointer to first element node + PNode pTail {}; // Pointer to last element node + PNode pLast {}; // Pointer to last node accessed + +public: + LinkedList() = default; // Constructor + LinkedList(const LinkedList& list); // Copy constructor + LinkedList& operator=(const LinkedList& list); // Assignment operator + void addHead(T* pObj); // Add an object to the head + void addTail(T* pObj); // Add an object to the tail + T* getHead(); // Get the object at the head + T* getTail(); // Get the object at the head + T* getNext(); // Get the next object + T* getPrevious(); // Get the previous object + +private: + // Node class definition + class Node + { + public: + size_t index {}; // Index of element + T* pObject {}; // Reference to object + PNode pNext {}; // Pointer to next node + PNode pPrevious {}; // Pointer to previous node + + Node(T* pObj) : pObject {new T {*pObj}} {} // Constructor + Node(const Node& node) : index {node.index}, pObject {new T {*node.pObject}} {} // Copy constructor + + ~Node() { delete pObject; } // Destructor + }; +}; + + +// Copy constructor template +template LinkedList::LinkedList(const LinkedList& list) +{ + if (list.pHead) + { // If there is a first element + pTail = pHead = std::make_shared(*list.pHead); // Duplicate it + + PNode pTemp; + PNode pCurrent = list.pHead; + while (pCurrent = pCurrent->pNext) + { // Duplicate any further nodes + pTemp = pTail; // Save the address of the last + pTail = std::make_shared(*pCurrent); // Make the new one the last + pTemp->pNext = pTail; // Set the next pointer of old last + pTail->pPrevious = pTemp; // Set previous pointer of new last + } + } +} + +// Assignment operator template +template LinkedList& LinkedList::operator=(const LinkedList& list) +{ + if (this == &list) // Check for rhs same as lhs + return *this; + + PNode pCurrent; + if (list.pHead) + { + pTail = pHead = std::make_shared(*list.pHead); + Node* pTemp {}; + pCurrent = list.pHead; + while (pCurrent = pCurrent->pNext) + { + pTemp = pTail; + pTail = std::make_shared(*pCurrent); + pTemp->pNext = pTail; + pTail->pPrevious = pTemp; + pTemp = pTail; + } + } + return *this; +} + +// Template function member to add an object to the head of the list +template void LinkedList::addHead(T* pObj) +{ + if (pHead) + { + pHead->pPrevious = std::make_shared(pObj); + pHead->pPrevious->pNext = pHead; + pHead = pHead->pPrevious; + } + else + pHead = pTail = std::make_shared(pObj); + pLast = pHead; +} + +// Template function member to add an object to the tail of the list +template void LinkedList::addTail(T* pObj) +{ + if (pTail) + { + pTail->pNext = std::make_shared(pObj); + pTail->pNext->pPrevious = pTail; + pTail = pTail->pNext; + } + else + pHead = pTail = std::make_shared(pObj); + pLast = pTail; +} + +// Template function member to get the object at the head of the list +template T* LinkedList::getHead() +{ + pLast = pHead; + if (pHead) + return pHead->pObject; + else + return nullptr; +} + +// Template function member to get the object at the tail of the list +template T* LinkedList::getTail() +{ + pLast = pTail; + if (pTail) + return pTail->pObject; + else + return nullptr; +} + +// Template function member to get the next object +template T* LinkedList::getNext() +{ + if (pLast) + if (pLast = pLast->pNext) + return pLast->pObject; + return nullptr; +} + +// Template function member to get the previous object +template T* LinkedList::getPrevious() +{ + if (pLast) + if (pLast = pLast->pPrevious) + return pLast->pObject; + return nullptr; +} + +#endif //LINKEDLISTT_H \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 16/Soln16_03/Soln16_03.cpp b/9781484200087_Exercise_Solutions/Chapter 16/Soln16_03/Soln16_03.cpp new file mode 100644 index 0000000..68fa0c3 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 16/Soln16_03/Soln16_03.cpp @@ -0,0 +1,55 @@ +// Exercise 16.3 Exercising the SparseArray class template with the LinkedList class template +#include "SparseArrayT.h" +#include "LinkedListT.h" +#include +#include +#include +using std::string; +using List = LinkedList ; + +int main() +{ + string text; // Stores input prose or poem + std::cout << "\nEnter a poem or prose over one or more lines." + << "Terminate the input with #:\n"; + getline(std::cin, text, '#'); + + SparseArray lists; // Sparse array of linked lists + string letters {"ABCDEFGHIJKLMNOPQRSTUVWXYZ"}; + + // Extract words and store in the appropriate list + // A list in the SparseArray is selected by the index in letters of the first letter in a word. + string word; // Stores a word + string separators {" \n\t,.\"?!;:"}; // Separators between words + size_t start {}; // Start of a word + size_t end {}; // separator position after a word + while(string::npos != (start = text.find_first_not_of(separators, start))) + { + end = text.find_first_of(separators, start+1); + word = text.substr(start,end-start); + lists[letters.find(std::toupper(word[0]))].addTail(&word); + start = end; + } + + // List the words in order 5 to a line + const size_t perline {5}; + size_t count {}; // Word counter + string* pStr; + for (size_t i {}; i < 26; ++i) + { + if (!lists.element_exists(i)) + continue; + pStr = lists[i].getHead(); + count = 0; + + while(pStr) + { + std::cout << *pStr << ' '; + if(!(++count % perline)) + std::cout << std::endl; + pStr = lists[i].getNext(); + } + std::cout << std::endl; + } + std::cout << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 16/Soln16_03/SparseArrayT.h b/9781484200087_Exercise_Solutions/Chapter 16/Soln16_03/SparseArrayT.h new file mode 100644 index 0000000..20a6513 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 16/Soln16_03/SparseArrayT.h @@ -0,0 +1,167 @@ +// Exercise 16.3 SparseArrayT.h +// SparseArray class template definition +/* +The SparseArray template uses smart pointers to manage Node objects that are array elements. +This means a destructor is not required for SparseArray. +Raw pointers to objects are stored in the array and objects are copied in the free store +so the nested Node class needs a destructor. +If the sparse array could only store smart pointers, it could only be used for objects in the free store. +A raw pointer can pointer to either free store objects or automatic objects. +*/ + +#ifndef SPARSEARRAYT_H +#define SPARSEARRAYT_H +#include +#include +#include +using std::string; + +template class SparseArray +{ + class Node; + using PNode = std::shared_ptr < Node >; +private: + PNode pFirst; // Pointer to first element node + PNode pLast; // Pointer to last element node + +public: + SparseArray() = default; // Constructor + SparseArray(const SparseArray& array); // Copy constructor + SparseArray& operator=(const SparseArray& array); // Assignment operator + T& operator[](size_t index); // Subscript SparseArray + bool element_exists(size_t index); // Return true if element exists + void show(); // display array elements + +private: + // Node class definition + class Node + { + public: + size_t index {}; // Index of element + T* pObject; // Address of object + PNode pNext; // Pointer to next node + PNode pPrevious; // Pointer to previous node + + Node(size_t newIndex) : index(newIndex), pObject(new T) {} // Constructor + Node(const Node& node) : index(node.index), pObject(new T(*node.pObject)) {} // Copy constructor + ~Node(){ delete pObject; } // Destructor + }; +}; + + +// Copy constructor template +template SparseArray::SparseArray(const SparseArray& array) +{ + if (array.pFirst) + { // If there is a first element + pLast = pFirst = std::make_shared(*array.pFirst); // Duplicate it + + PNode pTemp; + PNode pCurrent {array.pFirst}; + while (pCurrent = pCurrent->pNext) + { // Duplicate any further nodes + pTemp = pLast; // Save the address of the last + pLast = std::make_shared(*pCurrent); // Make the new one the last + pTemp->pNext = pLast; // Set the next pointer of old last + pLast->pPrevious = pTemp; // Set previous pointer of new last + } + } +} + +// Assignment operator template +template SparseArray& SparseArray::operator=(const SparseArray& array) +{ + if (this == &array) // Check for rhs same as lhs + return *this; + + PNode pCurrent; + if (array.pFirst) + { + pLast = pFirst = std::make_shared(*array.pFirst); + Node* pTemp; + pCurrent = array.pFirst; + while (pCurrent = pCurrent->pNext) + { + pTemp = pLast; + pLast = std::make_shared(*pCurrent); + pTemp->pNext = pLast; + pLast->pPrevious = pTemp; + pTemp = pLast; + } + } + return *this; +} + +// Subscript operator for non-const objects +template T& SparseArray::operator[](size_t index) +{ + // Search the list for a node corresponding to index + PNode pCurrent {pFirst}; + while (pCurrent) + { + if (pCurrent->index == index) + return *pCurrent->pObject; + if (pCurrent->index > index) + break; + pCurrent = pCurrent->pNext; + } + + // If we get to here, the element doesn't exist + // so we must create one + PNode pNode = std::make_shared(index); + pNode->pObject = new T; + if (pCurrent) // If its not the end of the list we must insert the element + { + if (pCurrent->pPrevious) // If current has a previous node just insert the new node + { + pCurrent->pPrevious->pNext = pNode; + pNode->pPrevious = pCurrent->pPrevious; + pCurrent->pPrevious = pNode; + pNode->pNext = pCurrent; + } + else // Current must be the first so add new node as first + { + pNode->pNext = pCurrent; + pCurrent->pPrevious = pNode; + pFirst = pNode; + } + } + else { // We must append the element + if (pLast) + { + pLast->pNext = pNode; + pNode->pPrevious = pLast; + pLast = pNode; + } + else + pFirst = pLast = pNode; + } + return *pNode->pObject; // Return the new element +} + +// Display the elements of a SparseArray +template void SparseArray::show() +{ + PNode pCurrent {pFirst}; + while (pCurrent) + { + std::cout << "\n[" << std::setw(2) << pCurrent->index << "] = " << *pCurrent->pObject; + pCurrent = pCurrent->pNext; + } + std::cout << std::endl; +} + +// Test for existence of element at index +template +bool SparseArray::element_exists(size_t index) +{ + PNode p {pFirst}; + while (p) + { + if (p->index == index) return true; + p = p->pNext; + } + return false; +} + +#endif //SPARSEARRAY_H \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 16/Soln16_04/Soln16_04.cpp b/9781484200087_Exercise_Solutions/Chapter 16/Soln16_04/Soln16_04.cpp new file mode 100644 index 0000000..3aae8df --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 16/Soln16_04/Soln16_04.cpp @@ -0,0 +1,55 @@ +// Exercise 16.4 Exercising the SparseArray class template for an array of arrays +/* +The example uses a SparseArray of elements that are SparseArray objects, +each of which stores words that have the same initial letter, ignoring case. +This is different from Soln16_03 where the linked list stored pointer to words. +The insert() function is used to add to an array of words with a given inital letter. +*/ +#include "SparseArrayT.h" +#include +#include +using std::string; + +int main() +{ + string text; // Stores input prose or poem + std::cout << "\nEnter a poem or prose over one or more lines." + << "Terminate the input with #:\n"; + getline(std::cin, text, '#'); + + SparseArray< SparseArray > arrays; // Sparse array of arrays of strings + string letters {"ABCDEFGHIJKLMNOPQRSTUVWXYZ"}; + + // Extract words and store in the appropriate list + string word; // Stores a word + string separators {" \n\t,.\"?!;:"}; // Separators between words + size_t start {}; // Start of a word + size_t end {}; // separator position after a word + while (string::npos != (start = text.find_first_not_of(separators, start))) + { + end = text.find_first_of(separators, start + 1); + word = text.substr(start, end - start); + arrays[letters.find(toupper(word[0]))].insert(&word); + start = end; + } + + // List the words in order 5 to a line + const size_t perline {5}; + size_t count {}; // Word counter + size_t j {}; + for (size_t i {}; i < 26; ++i) + { + if (!arrays.element_exists(i)) + continue; + j = 0; + count = 0; + while ((word = arrays[i][j++]).length()) + { + std::cout << word << ' '; + if (!(++count % perline)) + std::cout << std::endl; + } + std::cout << std::endl; + } + std::cout << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 16/Soln16_04/SparseArrayT.h b/9781484200087_Exercise_Solutions/Chapter 16/Soln16_04/SparseArrayT.h new file mode 100644 index 0000000..aaf034c --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 16/Soln16_04/SparseArrayT.h @@ -0,0 +1,182 @@ +// Exercise 16.4 SparseArrayT.h +// SparseArray class template definition +/* +The insert() member inserts a new element following the last element. +This is used in the exercise to add elements to an element of a SparseArray that is a SparseArray. +*/ + +#ifndef SPARSEARRAYT_H +#define SPARSEARRAYT_H +#include +#include +#include +using std::string; + +template class SparseArray +{ + class Node; + using PNode = std::shared_ptr < Node >; +private: + PNode pFirst; // Pointer to first element node + PNode pLast; // Pointer to last element node + +public: + SparseArray() = default; // Constructor + SparseArray(const SparseArray& array); // Copy constructor + SparseArray& operator=(const SparseArray& array); // Assignment operator + T& operator[](size_t index); // Subscript SparseArray + bool element_exists(size_t index); // Return true if element exists + void show(); // display array elements + void insert(T* pObj); // Insert an element after the last + +private: + // Node class definition + class Node + { + public: + size_t index {}; // Index of element + T* pObject; // Address of object + PNode pNext; // Pointer to next node + PNode pPrevious; // Pointer to previous node + + Node(size_t newIndex) : index(newIndex), pObject(new T) {} // Constructor + Node(const Node& node) : index(node.index), pObject(new T(*node.pObject)) {} // Copy constructor + ~Node(){ delete pObject; } // Destructor + }; +}; + + +// Copy constructor template +template SparseArray::SparseArray(const SparseArray& array) +{ + if (array.pFirst) + { // If there is a first element + pLast = pFirst = std::make_shared(*array.pFirst); // Duplicate it + + PNode pTemp; + PNode pCurrent {array.pFirst}; + while (pCurrent = pCurrent->pNext) + { // Duplicate any further nodes + pTemp = pLast; // Save the address of the last + pLast = std::make_shared(*pCurrent); // Make the new one the last + pTemp->pNext = pLast; // Set the next pointer of old last + pLast->pPrevious = pTemp; // Set previous pointer of new last + } + } +} + +// Assignment operator template +template SparseArray& SparseArray::operator=(const SparseArray& array) +{ + if (this == &array) // Check for rhs same as lhs + return *this; + + PNode pCurrent; + if (array.pFirst) + { + pLast = pFirst = std::make_shared(*array.pFirst); + Node* pTemp; + pCurrent = array.pFirst; + while (pCurrent = pCurrent->pNext) + { + pTemp = pLast; + pLast = std::make_shared(*pCurrent); + pTemp->pNext = pLast; + pLast->pPrevious = pTemp; + pTemp = pLast; + } + } + return *this; +} + +// Subscript operator for non-const objects +template T& SparseArray::operator[](size_t index) +{ + // Search the list for a node corresponding to index + PNode pCurrent {pFirst}; + while (pCurrent) + { + if (pCurrent->index == index) + return *pCurrent->pObject; + if (pCurrent->index > index) + break; + pCurrent = pCurrent->pNext; + } + + // If we get to here, the element doesn't exist + // so we must create one + PNode pNode = std::make_shared(index); + pNode->pObject = new T; + if (pCurrent) // If its not the end of the list we must insert the element + { + if (pCurrent->pPrevious) // If current has a previous node just insert the new node + { + pCurrent->pPrevious->pNext = pNode; + pNode->pPrevious = pCurrent->pPrevious; + pCurrent->pPrevious = pNode; + pNode->pNext = pCurrent; + } + else // Current must be the first so add new node as first + { + pNode->pNext = pCurrent; + pCurrent->pPrevious = pNode; + pFirst = pNode; + } + } + else { // We must append the element + if (pLast) + { + pLast->pNext = pNode; + pNode->pPrevious = pLast; + pLast = pNode; + } + else + pFirst = pLast = pNode; + } + return *pNode->pObject; // Return the new element +} + +// Display the elements of a SparseArray +template void SparseArray::show() +{ + PNode pCurrent {pFirst}; + while (pCurrent) + { + std::cout << "\n[" << std::setw(2) << pCurrent->index << "] = " << *pCurrent->pObject; + pCurrent = pCurrent->pNext; + } + std::cout << std::endl; +} + +// Test for existence of element at index +template +bool SparseArray::element_exists(size_t index) +{ + PNode p {pFirst}; + while (p) + { + if (p->index == index) return true; + p = p->pNext; + } + return false; +} + +// Insert an element after the last +template void SparseArray::insert(T* pObj) +{ + PNode pNode; + if (pLast) // If there is a last element add the new one after it + { + pNode = std::make_shared(pLast->index + 1); + pLast->pNext = pNode; + pNode->pPrevious = pLast; + pLast = pNode; + } + else // Otherwise the new one is the first + pFirst = pLast = pNode = std::make_shared(0); + if (pObj) // If there is an object + pNode->pObject = new T(*pObj); // Create a duplicate + else + pNode->pObject = new T; // Otherwise, create a default T +} +#endif //SPARSEARRAY_H \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 17/Soln17_01/Soln17_01.cpp b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_01/Soln17_01.cpp new file mode 100644 index 0000000..93c977a --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_01/Soln17_01.cpp @@ -0,0 +1,13 @@ +// Exercise 17.1 Using the Time class with an overloaded insertion operator. + +#include "Time.h" +#include + +int main() +{ + Time period1(10,30,25); + Time period2(1, 70,90); + std::cout << "\nPeriod 1 is " << period1 + << "\nPeriod 2 is " << period2 + << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 17/Soln17_01/Time.cpp b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_01/Time.cpp new file mode 100644 index 0000000..5c9f911 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_01/Time.cpp @@ -0,0 +1,27 @@ +// Exercise 17.1 Time.cpp +//Time class implementation + +#include "Time.h" +#include +#include + +// Constructor - implemented to allow specification of minutes and seconds more than 59 +Time::Time(int h, int m, int s) +{ + seconds = s%60; // Seconds left after removing minutes + minutes = m + s/60; // Minutes plus minutes from seconds + hours = h + minutes/60; // Hours plus hours from minutes + minutes %= 60; // Minutes left after removing hours +} + +// Insertion operator +std::ostream& operator <<(std::ostream& out, const Time& rT) +{ + out << ' ' << rT.getHours() << ':'; + char fillCh {out.fill('0')}; // Set fill for leading zeros + + out << std::setw(2) << rT.getMinutes() << ':' + << std::setw(2) << rT.getSeconds() << ' '; + out.fill(fillCh); // Restore old fill character + return out; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 17/Soln17_01/Time.h b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_01/Time.h new file mode 100644 index 0000000..dabc2e4 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_01/Time.h @@ -0,0 +1,25 @@ +// Exercise 17.1 Time.h +// Definition of Time class + +#ifndef TIME_H +#define TIME_H +#include + +class Time +{ +private: + int hours {}; + int minutes {}; + int seconds {}; + + public: + Time() = default; + Time(int h, int m, int s); + int getHours()const { return hours; } + int getMinutes()const { return minutes; } + int getSeconds()const { return seconds; } +}; + +std::ostream& operator <<(std::ostream& out, const Time& rT); // Overloaded insertion operator declaration + +#endif //TIME_H \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 17/Soln17_02/Soln17_02.cpp b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_02/Soln17_02.cpp new file mode 100644 index 0000000..b000dd2 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_02/Soln17_02.cpp @@ -0,0 +1,17 @@ +// Exercise 17.2 Using the Time class with an overloaded extraction operator. +// The extraction operator is implemented as a friend of the Time class +#include "Time.h" +#include + +int main() +{ + Time period1; + Time period2; + std::cout << "\nEnter a time as hours:minutes:seconds, and press Enter: "; + std::cin >> period1; + std::cout << "\nEnter another time as hours:minutes:seconds, and press Enter: "; + std::cin >> period2; + std::cout << "\nPeriod 1 is " << period1 + << "\nPeriod 2 is " << period2 + << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 17/Soln17_02/Time.cpp b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_02/Time.cpp new file mode 100644 index 0000000..d8c2e1e --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_02/Time.cpp @@ -0,0 +1,41 @@ +// Exercise 17.2 Time.cpp +// Time class implementation + +#include "Time.h" +#include +#include + +// Constructor +Time::Time(int h, int m, int s) +{ + seconds = s%60; // Seconds left after removing minutes + minutes = m + s/60; // Minutes plus minutes from seconds + hours = h + minutes/60; // Hours plus hours from minutes + minutes %= 60; // Minutes left after removing hours +} + +// Insertion operator +std::ostream& operator <<(std::ostream& out, const Time& rT) +{ + out << ' ' << rT.getHours() << ':'; + char fillCh {out.fill('0')}; // Set fill for leading zeros + + out << std::setw(2) << rT.getMinutes() << ':' + << std::setw(2) << rT.getSeconds() << ' '; + out.fill(fillCh); // Restore old fill character + return out; +} + +// Extraction operator +std::istream& operator>> (std::istream& in, Time& rT) +{ + char ch {}; // Stores ':' + in >> rT.hours >> ch >> rT.minutes >> ch >> rT.seconds; + + // Ensure seconds and minutes less than 60 + rT.minutes += rT.seconds/60; + rT.hours += rT.minutes/60; + rT.minutes %= 60; + rT.seconds %= 60; + return in; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 17/Soln17_02/Time.h b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_02/Time.h new file mode 100644 index 0000000..d4c6f47 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_02/Time.h @@ -0,0 +1,28 @@ +// Exercise 17.2 Time.h +// Definition of Time class + +#ifndef TIME_H +#define TIME_H +#include + +class Time +{ + private: + int hours {}; + int minutes {}; + int seconds {}; + + public: + Time() = default; + Time(int h, int m, int s); + + int getHours()const { return hours; } + int getMinutes()const { return minutes; } + int getSeconds()const { return seconds; } + + friend std::istream& operator>> (std::istream& in, Time& rT); // Friend extraction operator +}; + +std::ostream& operator <<(std::ostream& out, const Time& rT); // Overloaded insertion operator declaration + +#endif //TIME_H \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 17/Soln17_03a/Soln17_03a.cpp b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_03a/Soln17_03a.cpp new file mode 100644 index 0000000..1c5fd0a --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_03a/Soln17_03a.cpp @@ -0,0 +1,38 @@ +// Exercise 17.3a Writing Time class 0bjects to a file. + +#include "Time.h" +#include +#include +#include +#include + +using std::string; + +int main() +{ + string fileName; + std::cout << "Enter the name of the file you want to write, including the path: "; + std::getline(std::cin, fileName); + std::ofstream outFile {fileName}; + if(!outFile) + { + std::cerr << "Failed to open output file. Program terminated.\n"; + exit(1); + } + + Time period; + char ch {'n'}; + + do + { + std::cout << "Enter a time as hours:minutes:seconds, and press Enter: "; + std::cin >> period; + outFile << period; + std::cout << "Do you want to enter another?(y or n): "; + std::cin >> ch; + }while(std::toupper(ch)=='Y'); + + outFile.close(); + + std::cout << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 17/Soln17_03a/Time.cpp b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_03a/Time.cpp new file mode 100644 index 0000000..83db75a --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_03a/Time.cpp @@ -0,0 +1,41 @@ +// Exercise 17.3a Time.cpp +// Time class implementation + +#include "Time.h" +#include +#include + +// Constructor +Time::Time(int h, int m, int s) +{ + seconds = s%60; // Seconds left after removing minutes + minutes = m + s/60; // Minutes plus minutes from seconds + hours = h + minutes/60; // Hours plus hours from minutes + minutes %= 60; // Minutes left after removing hours +} + +// Insertion operator +std::ostream& operator <<(std::ostream& out, const Time& rT) +{ + out << ' ' << rT.getHours() << ':'; + char fillCh {out.fill('0')}; // Set fill for leading zeros + + out << std::setw(2) << rT.getMinutes() << ':' + << std::setw(2) << rT.getSeconds() << ' '; + out.fill(fillCh); // Restore old fill character + return out; +} + +// Extraction operator +std::istream& operator>> (std::istream& in, Time& rT) +{ + char ch {}; // Stores ':' + in >> rT.hours >> ch >> rT.minutes >> ch >> rT.seconds; + + // Ensure seconds and minutes less than 60 + rT.minutes += rT.seconds/60; + rT.hours += rT.minutes/60; + rT.minutes %= 60; + rT.seconds %= 60; + return in; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 17/Soln17_03a/Time.h b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_03a/Time.h new file mode 100644 index 0000000..c3472ae --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_03a/Time.h @@ -0,0 +1,28 @@ +// Exercise 17.3a Time.h +// Definition of Time class + +#ifndef TIME_H +#define TIME_H +#include + +class Time +{ + private: + int hours {}; + int minutes {}; + int seconds {}; + + public: + Time() = default; + Time(int h, int m, int s); + + int getHours()const { return hours; } + int getMinutes()const { return minutes; } + int getSeconds()const { return seconds; } + + friend std::istream& operator>> (std::istream& in, Time& rT); // Friend extraction operator +}; + +std::ostream& operator <<(std::ostream& out, const Time& rT); // Overloaded insertion operator declaration + +#endif //TIME_H \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 17/Soln17_03b/Soln17_03b.cpp b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_03b/Soln17_03b.cpp new file mode 100644 index 0000000..fbc64a7 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_03b/Soln17_03b.cpp @@ -0,0 +1,35 @@ +// Exercise 17.3b Reading Time class 0bjects from a file. + +#include "Time.h" +#include +#include +#include + +using std::string; + +int main() +{ + string fileName; + std::cout << "Enter the name of the file you want to read, including the path: "; + std::getline(std::cin, fileName); + std::ifstream inFile {fileName}; + if(!inFile) + { + std::cerr << "Failed to open input file. Program terminated.\n"; + exit(1); + } + + Time period; + size_t count {}; + const size_t perline {5}; + std::cout << "Times on file are:\n"; + + while(!(inFile >> period).eof()) + { + std::cout << period; + if(!(++count % perline)) + std::cout << std::endl; // Newline every 5th output + } + std::cout << std::endl; + inFile.close(); +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 17/Soln17_03b/Time.cpp b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_03b/Time.cpp new file mode 100644 index 0000000..cdefa05 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_03b/Time.cpp @@ -0,0 +1,41 @@ +// Exercise 17.3b Time.cpp +// Time class implementation + +#include "Time.h" +#include +#include + +// Constructor +Time::Time(int h, int m, int s) +{ + seconds = s%60; // Seconds left after removing minutes + minutes = m + s/60; // Minutes plus minutes from seconds + hours = h + minutes/60; // Hours plus hours from minutes + minutes %= 60; // Minutes left after removing hours +} + +// Insertion operator +std::ostream& operator <<(std::ostream& out, const Time& rT) +{ + out << ' ' << rT.getHours() << ':'; + char fillCh {out.fill('0')}; // Set fill for leading zeros + + out << std::setw(2) << rT.getMinutes() << ':' + << std::setw(2) << rT.getSeconds() << ' '; + out.fill(fillCh); // Restore old fill character + return out; +} + +// Extraction operator +std::istream& operator>> (std::istream& in, Time& rT) +{ + char ch {}; // Stores ':' + in >> rT.hours >> ch >> rT.minutes >> ch >> rT.seconds; + + // Ensure seconds and minutes less than 60 + rT.minutes += rT.seconds/60; + rT.hours += rT.minutes/60; + rT.minutes %= 60; + rT.seconds %= 60; + return in; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 17/Soln17_03b/Time.h b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_03b/Time.h new file mode 100644 index 0000000..e543a42 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_03b/Time.h @@ -0,0 +1,28 @@ +// Exercise 17.3b Time.h +// Definition of Time class + +#ifndef TIME_H +#define TIME_H +#include + +class Time +{ + private: + int hours {}; + int minutes {}; + int seconds {}; + + public: + Time() = default; + Time(int h, int m, int s); + + int getHours()const { return hours; } + int getMinutes()const { return minutes; } + int getSeconds()const { return seconds; } + + friend std::istream& operator>> (std::istream& in, Time& rT); // Friend extraction operator +}; + +std::ostream& operator <<(std::ostream& out, const Time& rT); // Overloaded insertion operator declaration + +#endif //TIME_H \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 17/Soln17_04a/Soln17_04a.cpp b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_04a/Soln17_04a.cpp new file mode 100644 index 0000000..e005174 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_04a/Soln17_04a.cpp @@ -0,0 +1,93 @@ +// Exercise 17.4a Removing surplus spaces from a stream. +#include +#include +#include +using std::string; + +// Program to remove surplus spaces from a stream +// We must treat the standard input streams as a special case. +// Because cin has no end of file, so we must determine end of input differently. + +// Function to copy one stream to another removing surplus spaces +void copy(std::istream& in, std::ostream& out, char end = ' ') +{ + char ch {}; + bool gotSpace {false}; // True for first space in a sequence + + while(in.get(ch)) + { + if(end != ' ' && end == ch) // Check for end on cin + break; + if(ch==' ') + if(gotSpace) + continue; + else + gotSpace= true; + else + gotSpace = false; + out.put(ch); + } +} + + +// Requires two command line arguments identifying the input and output streams +// First argument is cin or the name and path of the input file +// Second argument is cout or the name and path of the output file +int main(int argc, char* argv[]) +{ + if(argc < 3) + { + std::cout << "This program requires two command line arguments." + << "\nThe first command line argument is the input file name and path, or cin." + << "\nThe second is the output file name and path, or cout.\n"; + exit(1); + } + + string in {argv[1]}; + string out {argv[2]}; + std::cout << "Reading from " << in << " and writing to " << out << std::endl; + +// std::cout << "Reading from " << argv[1] << " and writing to " << argv[2] << std::endl; + + bool kbd {in == "cin" || in == "std::cin"}; // Standard input stream indicator + bool scrn {out == "cout" || out == "std::cout"}; // Standard output stream indicator + char end {}; // Indicates end of input on cin; + if(kbd) + { + std::cout << "Enter the character you want to indicate end of input: "; + std::cin >> end; + if(scrn) + copy(std::cin, std::cout, end); + else { + std::ofstream outFile {out}; + if(!outFile) + { + std::cerr << "Failed to open output file. Program terminated.\n"; + exit(1); + } + copy(std::cin, outFile, end); + } + } + else + { + std::ifstream inFile {in}; + if(!inFile) + { + std::cerr << "Failed to open input file. Program terminated.\n"; + exit(1); + } + if(scrn) + copy(inFile, std::cout); + else + { + std::ofstream outFile {out}; + if(!outFile) + { + std::cerr << "Failed to open output file. Program terminated.\n"; + exit(1); + } + copy(inFile, outFile); + } + } + std::cout << "\n Stream copy complete." << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 17/Soln17_04b/Soln17_04b.cpp b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_04b/Soln17_04b.cpp new file mode 100644 index 0000000..5456ea7 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_04b/Soln17_04b.cpp @@ -0,0 +1,83 @@ +// Exercise 17.4b Converting contents of a stream to upper case. +#include +#include +#include +#include +using std::string; + +// Program to convert contents of a stream to upper case +// We must treat the standard input streams as a special case. +// Because cin has no end of file, so we must determine end of input differently. + +// Function to copy one stream to another converting to upper case +void copy(std::istream& in, std::ostream& out, char end = ' ') +{ + char ch {}; + + while(in.get(ch)) + { + if(end != ' ' && end == ch) // Check for end on cin + break; + out.put(std::toupper(ch)); + } +} + + +// Requires two command line arguments identifying the input and output streams +// First argument is cin or the name and path of the input file +// Second argument is cout or the name and path of the output file +int main(int argc, char* argv[]) { + if(argc<3) + { + std::cout << "This program requires two command line arguments." + << "\nThe first command line argument is the input file name and path, or cin." + << "\nThe second is the output file name and path, or cout.\n"; + exit(1); + } + + string in {argv[1]}; + string out {argv[2]}; + std::cout << "Reading from " << in << " and writing to " << out << std::endl; + + bool kbd {in == "cin" || in == "std::cin"}; // Standard input stream indicator + bool scrn {out == "cout" || out == "std::cout"}; // Standard output stream indicator + char end {}; // Indicates end of input on cin; + if (kbd) + { + std::cout << "\nEnter the character you want to indicate end of input: "; + std::cin >> end; + if(scrn) + copy(std::cin, std::cout, end); + else + { + std::ofstream outFile {out}; + if(!outFile) + { + std::cerr << "Failed to open output file. Program terminated.\n"; + exit(1); + } + copy(std::cin, outFile, end); + } + } + else { + std::ifstream inFile {in}; + if(!inFile) + { + std::cerr << "Failed to open input file. Program terminated.\n"; + exit(1); + } + if(scrn) + copy(inFile, std::cout); + else + { + std::ofstream outFile {out}; + if(!outFile) + { + std::cerr << "Failed to open output file. Program terminated.\n"; + exit(1); + } + copy(inFile, outFile); + } + } + std::cout << "\n Stream copy complete." << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 17/Soln17_05/Box.h b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_05/Box.h new file mode 100644 index 0000000..265ae0f --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_05/Box.h @@ -0,0 +1,53 @@ +// Box.h +#ifndef BOX_H +#define BOX_H +#include +#include +#include + +class Box +{ +protected: + double length {1.0}; + double width {1.0}; + double height {1.0}; + +public: + static const Box nullBox; // Box equivalent of nullptr + +public: + // Constructors + Box(double lv, double wv, double hv) : length {lv}, width {wv}, height {hv} {} + + Box() = default; // Default constructor + + Box(const Box& box) // Copy constructor + : length {box.length}, width {box.width}, height {box.height} {} + + virtual double volume() const // Calculate the volume + { return length*width*height; } + + // Comparison operators for equality and inequality + bool operator==(const Box& box) const { return length == box.length && width == box.width && height == box.height; } + bool operator!=(const Box& box) const { return !(*this == box); } + + // Stream extraction and insertion + friend std::ostream& operator<<(std::ostream& out, const Box& box); + friend std::istream& operator>>(std::istream& in, Box& box); +}; +static const Box nullBox {0, 0, 0}; + +// Stream output +inline std::ostream& operator<<(std::ostream& out, const Box& box) +{ + return out << std::setw(10) << box.length << ' ' + << std::setw(10) << box.width << ' ' + << std::setw(10) << box.height << '\n'; +} + +// Stream input +inline std::istream& operator>>(std::istream& in, Box& box) +{ + return in >> box.length >> box.width >> box.height; +} +#endif diff --git a/9781484200087_Exercise_Solutions/Chapter 17/Soln17_05/LinkedList.cpp b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_05/LinkedList.cpp new file mode 100644 index 0000000..4d4834e --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_05/LinkedList.cpp @@ -0,0 +1,113 @@ +#include "LinkedList.h" +#include + +// Copy constructor +LinkedList::LinkedList(const LinkedList& list) +{ + if (list.pHead) + { // If there is a first element + pTail = pHead = std::make_shared(*list.pHead); // Duplicate it + + PNode pTemp; + PNode pCurrent = list.pHead; + while (pCurrent = pCurrent->pNext) + { // Duplicate any further nodes + pTemp = pTail; // Save the address of the last + pTail = std::make_shared(*pCurrent); // Make the new one the last + pTemp->pNext = pTail; // Set the next pointer of old last + pTail->pPrevious = pTemp; // Set previous pointer of new last + } + } +} + +// Assignment operator +LinkedList& LinkedList::operator=(const LinkedList& list) +{ + if (this == &list) // Check for rhs same as lhs + return *this; + + PNode pCurrent; + if (list.pHead) + { + pTail = pHead = std::make_shared(*list.pHead); + PNode pTemp {}; + pCurrent = list.pHead; + while (pCurrent = pCurrent->pNext) + { + pTemp = pTail; + pTail = std::make_shared(*pCurrent); + pTemp->pNext = pTail; + pTail->pPrevious = pTemp; + pTemp = pTail; + } + } + return *this; +} + +// Add a Box object to the head of the list +void LinkedList::addHead(Box& box) +{ + if (pHead) + { + pHead->pPrevious = std::make_shared(box); + pHead->pPrevious->pNext = pHead; + pHead = pHead->pPrevious; + } + else + pHead = pTail = std::make_shared(box); + pLast = pHead; +} + +// Add a Box object to the tail of the list +void LinkedList::addTail(Box& box) +{ + if (pHead) + { + pTail->pNext = std::make_shared(box); + pTail->pNext->pPrevious = pTail; + pTail = pTail->pNext; + } + else + pHead = pTail = std::make_shared(box); + pLast = pTail; +} + +// Get the Box object at the head of the list +Box LinkedList::getHead() +{ + if (pHead) + { + pLast = pHead; + return *pHead->pBox; + } + else + return nullBox; +} + +// Get the Box object at the tail of the list +Box LinkedList::getTail() +{ + pLast = pTail; + if (pTail) + return *pTail->pBox; + else + return nullBox; +} + +// Get the next Box object +Box LinkedList::getNext() +{ + if (pLast) + if (pLast = pLast->pNext) + return *pLast->pBox; + return nullBox; +} + +// Get the previous Box object +Box LinkedList::getPrevious() +{ + if (pLast) + if (pLast = pLast->pPrevious) + return *pLast->pBox; + return nullBox; +} diff --git a/9781484200087_Exercise_Solutions/Chapter 17/Soln17_05/LinkedList.h b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_05/LinkedList.h new file mode 100644 index 0000000..e2b88b4 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_05/LinkedList.h @@ -0,0 +1,80 @@ +#ifndef LINKEDLIST_H +#define LINKEDLIST_H +#include +#include +#include +#include "Box.h" +using PBox = std::shared_ptr < Box > ; + +class LinkedList +{ + class Node; // Declaration required because class is not yet defined + using PNode = std::shared_ptr; // and we reference it here + + // Stream extraction and insertion + friend std::ostream& operator<<(std::ostream& out, LinkedList& list); + friend std::istream& operator>>(std::istream& in, LinkedList& list); + +private: + PNode pHead {}; // Pointer to first element node + PNode pTail {}; // Pointer to last element node + PNode pLast {}; // Pointer to last node accessed + +public: + LinkedList() = default; // Constructor + LinkedList(const LinkedList& list); // Copy constructor + LinkedList& operator=(const LinkedList& list); // Assignment operator + void addHead(Box& box); // Add a Box object to the head + void addTail(Box& box); // Add an object to the tail + Box getHead(); // Get the object at the head + Box getTail(); // Get the object at the head + Box getNext(); // Get the next object + Box getPrevious(); // Get the previous object + +private: + // Node class definition + class Node + { + public: + PBox pBox {}; // Pointer to Box object + PNode pNext {}; // Pointer to next node + PNode pPrevious {}; // Pointer to previous node + + Node(Box& box) : pBox {std::make_shared(box)} {} // Constructor + Node(const Node& node) : pBox {std::make_shared(*node.pBox)} {} // Copy constructor + }; +}; + +// Stream insertion operator +inline std::ostream& operator<<(std::ostream& out, LinkedList& list) +{ + Box box {list.getHead()}; + while (true) + { + if (typeid(out) == typeid(std::ofstream)) // Only write the flag if it is a file stream + out << (box != nullBox) << ' '; + if (box == nullBox) + break; + out << box; + box = list.getNext(); + } + return out; +} + +// Stream extraction operator +inline std::istream& operator>>(std::istream& in, LinkedList& list) +{ + bool isBox {}; + Box box; + while (true) + { + in >> isBox; // Read the flag indicating a Box follows + if (!isBox) // If there's no Box... + break; // ...we are done + in >> box; // Read a Box... + list.addTail(box); // ...and add it to the list + } + return in; +} + +#endif //LINKEDLIST_H \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 17/Soln17_05/Soln17_05.cpp b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_05/Soln17_05.cpp new file mode 100644 index 0000000..dbca466 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 17/Soln17_05/Soln17_05.cpp @@ -0,0 +1,49 @@ +// Ex17_05.cpp +// Writing & reading a linked list of Box objects +#include // For file streams +#include // For standard streams +#include // For vector +#include // For string type +#include "Box.h" +#include "LinkedList.h" +using std::string; + +int main() +try +{ + std::vector box_vector {Box {1, 2, 3}, Box {2, 3, 4}, Box {3, 4, 5}, Box {5, 6, 7}, + Box {6, 7, 8}, Box {7, 8, 9}}; + LinkedList boxes; + std::cout << "Box objects in the linked list are:\n"; + + for (auto& box : box_vector) + { + std::cout << box; + boxes.addTail(box); + } + + string filename; + std::cout << "Enter the name of the file you want to write, including the path: "; + std::getline(std::cin, filename); + std::ofstream out {filename}; + if (!out) + throw std::ios::failure {string {"Failed to open output file "} + filename}; + + out << boxes; // Write the list to the file + out.close(); + + LinkedList copy_boxes; // An empty list + std::ifstream in {filename}; // Create a file input stream + if (!in) // Make sure it's valid + throw std::ios::failure {string("Failed to open input file ") + filename}; + + std::cout << "Reading linked list of Box objects from the file...\n"; + in >> copy_boxes; // Read the list from the file + in.close(); // Close the input stream + + std::cout << "\nBox objects in the linked list read from the file are:\n" << copy_boxes; +} +catch (std::exception& ex) +{ + std::cout << typeid(ex).name() << ": " << ex.what() << std::endl; +} diff --git a/9781484200087_Exercise_Solutions/Chapter 2/Soln2_01.cpp b/9781484200087_Exercise_Solutions/Chapter 2/Soln2_01.cpp new file mode 100644 index 0000000..a8a8254 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 2/Soln2_01.cpp @@ -0,0 +1,24 @@ +// Exercise 2.1 Calculate the area of a circle of given radius. +// The value of pi is constant, and should not be changed within the program, +// so we recognize this by declaring it as a const. + +#include + +int main() +{ + + const float pi {3.14159f}; // Initialize constant variable + + float radius {}; + float areaOfCircle {}; + + std::cout << "This program will compute the area of a circle." << std::endl + << "It assumes that the value of pi is " << pi << "." << std::endl; + + std::cout << "Please enter the radius: "; + std::cin >> radius; + + areaOfCircle = pi * radius * radius; + + std::cout << "\nThe area of the circle is " << areaOfCircle << " square units." << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 2/Soln2_02.cpp b/9781484200087_Exercise_Solutions/Chapter 2/Soln2_02.cpp new file mode 100644 index 0000000..19ceae1 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 2/Soln2_02.cpp @@ -0,0 +1,31 @@ +// Exercise 2.2 This time, the user is also prompted to enter an integer that we can +// subsequently use to control the program's output. +// Note that setprecision() doesn't alter the calculated value of areaOfCircle; +// it's only used to control how this value is output. + +#include +#include + +int main() +{ + const float pi {3.14159f}; // Initialize constant variable + + float radius {}; + float areaOfCircle {}; + unsigned int sigFigs {}; + + std::cout << "This program will compute the area of a circle." << std::endl + << "It assumes that the value of pi is " << pi << "." << std::endl; + + std::cout << "Please enter the radius: "; + std::cin >> radius; + + std::cout << "Please enter the desired precision of the output (significant figures): "; + std::cin >> sigFigs; + + areaOfCircle = pi * radius * radius; + + std::cout << "The area of the circle is approximately equal to " + << std::setprecision(sigFigs) + << areaOfCircle << " square units." << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 2/Soln2_03.cpp b/9781484200087_Exercise_Solutions/Chapter 2/Soln2_03.cpp new file mode 100644 index 0000000..a87ceef --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 2/Soln2_03.cpp @@ -0,0 +1,19 @@ +// Exercise 2.3 Converting a length in inches to feet-and-inches. +#include + +int main() +{ + const int inches_per_foot {12}; + + long length_inches {}; + + std::cout << "This program converts inches into feet-and-inches.\n"; + std::cout << "Please enter the number of inches: "; + std::cin >> length_inches; + + long feet {length_inches / inches_per_foot}; + long inches {length_inches % inches_per_foot}; + + std::cout << "In " << length_inches << " inches there are " + << feet << " feet and " << inches << " inch(es)." << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 2/Soln2_04.cpp b/9781484200087_Exercise_Solutions/Chapter 2/Soln2_04.cpp new file mode 100644 index 0000000..f444a0b --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 2/Soln2_04.cpp @@ -0,0 +1,34 @@ +// Exercise 2.4 Calculating the height of a tree +#include +#include +#include + +int main() +{ + const double inches_per_foot {12.0}; + const double pi {3.14159265}; + const double pi_degrees {180.0}; + double d_feet {}; + double d_inches {}; + double angle {}; + double eye_height {}; + + std::cout << "Enter the distance from the tree in feet and inches: "; + std::cin >> d_feet >> d_inches; + double distance {d_feet + d_inches / inches_per_foot}; + + std::cout << "Enter the angle of the top of the tree in degrees: "; + std::cin >> angle; + angle *= pi/pi_degrees; // Convert angle to radians + + std::cout << "Enter your eye height from the ground in inches: "; + std::cin >> eye_height; + eye_height /= inches_per_foot; // Convert to feet + double height {eye_height + distance*std::tan(angle)}; // Tree height in feet + double height_feet {std::floor(height)}; + double height_inches {std::floor(inches_per_foot*(height - height_feet) + 0.5)}; + + std::cout << "\nThe height of the tree is " + << height_feet << " feet " + << height_inches << " inches.\n" << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 2/Soln2_05.cpp b/9781484200087_Exercise_Solutions/Chapter 2/Soln2_05.cpp new file mode 100644 index 0000000..15a7398 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 2/Soln2_05.cpp @@ -0,0 +1,23 @@ +// Exercise 2.5 Finding the largest of two integers without comparing them. +// The expressions depend on the fact that smaller/larger will be 0 with integer arithmetic +// whereas larger/smaller will be some positive non-zero integer. +#include + +int main() +{ + + long a {}; + long b {}; + + std::cout << "Enter a positive integer: "; + std::cin >> a; + std::cout << "Enter another different positive integer: "; + std::cin >> b; + + // The trick is to find arithmetic expressions for each of the larger + // and the smaller of the two integers + long larger {(a*(a / b) + b*(b / a)) / (a / b + b / a)}; + long smaller {(b*(a / b) + a*(b / a)) / (a / b + b / a)}; + std::cout << "The larger integer is " << larger << ".\n" + << "The smaller integer is " << smaller << "." << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 2/Soln2_06.cpp b/9781484200087_Exercise_Solutions/Chapter 2/Soln2_06.cpp new file mode 100644 index 0000000..89be025 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 2/Soln2_06.cpp @@ -0,0 +1,31 @@ +// Exercise 2.6 Calculating the Body Mass Index. +// In the expression for bmi, h_inches will be implicitly converted to double +// because the divisor is type double. + +// If you omit the std::fixed from the final output statement +// setprecision() specifies the number of digits precision. With std::fixed in effect +// it specifies the number of digits folllowing the decimal point. + +#include // For standard streams +#include // For stream manipulators + +int main() +{ + const double lbs_per_kg {2.2}; + const double inches_per_foot {12.0}; + const double meters_per_foot {0.3048}; + double w_lbs {}; + unsigned int h_feet {}; + unsigned int h_inches {}; + + std::cout << "Enter your weight in pounds: "; + std::cin >> w_lbs; + std::cout << "Enter you height in feet and inches: "; + std::cin >> h_feet >> h_inches; + + double w_kg {w_lbs/lbs_per_kg}; + double h_meters {}; + h_meters = meters_per_foot*(static_cast(h_feet) + h_inches/inches_per_foot); + double bmi {w_kg / (h_meters*h_meters)}; + std::cout << "Your BMI is " << std::fixed << std::setprecision(1) << bmi << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 3/Soln3_01.cpp b/9781484200087_Exercise_Solutions/Chapter 3/Soln3_01.cpp new file mode 100644 index 0000000..dc7de1b --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 3/Soln3_01.cpp @@ -0,0 +1,39 @@ +// Exercise 3.1 Output integer and its 1's complement in decimal and hexadecimal. + +// This tests how well you remember the stream manipulators as well as bitwise ~. +// You also need to be creative with the manipulators. +// The setw() manipulator only applies to the next output value so you must use it preceding each output value. +// std::internal causes the fill character, '0', to be used internal to the hexadecimal values. The field width has to be +// set appropriately to get the correct number of hex digits including the leading zeros. + +#include +#include + +int main() +{ + unsigned int value {}; + std::cout << "Enter a positive integer: "; + std::cin >> value; + unsigned int inverted_value {~value}; + + unsigned int hex_digits {2 * sizeof(unsigned int)}; // Hex digits in value + unsigned int width {hex_digits + 2}; // Add 2 for 0x prefix + unsigned int column_width {2 * width}; // Output column width + + // Output column headings + std::cout << std::right << std::setw(column_width) << "value" + << std::setw(column_width) << "~value" + << std::setw(column_width) << "~value+1" << std::endl; + + // Output hexadecimal values + std::cout << std::hex << std::showbase << std::internal << std::setfill('0') + << " " << std::setw(width) << value + << " " << std::setw(width) << inverted_value + << " " << std::setw(width) << inverted_value + 1 << std::endl; + + // Output decimal values + std::cout << std::dec << std::setfill(' ') + << std::setw(column_width) << value + << std::setw(column_width) << inverted_value + << std::setw(column_width) << inverted_value + 1 << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 3/Soln3_02.cpp b/9781484200087_Exercise_Solutions/Chapter 3/Soln3_02.cpp new file mode 100644 index 0000000..7d7b983 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 3/Soln3_02.cpp @@ -0,0 +1,36 @@ +// Exercise 3.2 Calculating the number of boxes that can be stored on a shelf, +// without overhang. We have to calculate how many boxes we can get into a row, +// and how many rows we can have, and then multiply these numbers together. +// The 'no overhang' problem is easily handled: casting from double to long +// (using static_cast<>()) ensures that the fractional part of the double value +// is omitted, and only whole boxes are counted. +// By including static_cast<>() in the code, we are effectively telling the +// compiler that we know what information will be lost in the cast. + +#include + +int main() +{ + const int inches_per_foot {12}; + + double shelf_length {}; + double shelf_depth {}; + double box_size {}; + + // Prompt the user for both the shelf and box dimensions + std::cout << "Enter shelf length (feet): "; + std::cin >> shelf_length; + + std::cout << "Enter shelf depth (feet): "; + std::cin >> shelf_depth; + + std::cout << "Enter length ofthe side of a box (inches): "; + std::cin >> box_size; + + // Calculating the number of whole boxes needed to fill the shelf. + long boxes {static_cast((shelf_length * inches_per_foot) / box_size) * + static_cast((shelf_depth * inches_per_foot) / box_size)}; + + // Displaying the number of boxes + std::cout << "The number of boxes that can be contained in a single layer is " << boxes << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 3/Soln3_03.cpp b/9781484200087_Exercise_Solutions/Chapter 3/Soln3_03.cpp new file mode 100644 index 0000000..d6a737c --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 3/Soln3_03.cpp @@ -0,0 +1,14 @@ +/********************************************************************************* +Exercise 3.3 The output from the code is 2. Here's the important statement again: + +unsigned int j {(k >> 4) & ~(~0 << 3)}; + +This question is an exercise in bit manipulation on k. +First, (k >> 4) shifts the bits in k 4 places to the right; +the bitwise representation of 430 is 110101110, +so a 4-bit shift leaves 11010. +Next, ~0 is composed of all 1s; shifting that three places to the left +and complementing the result will leave 111. +Finally, doing a bitwise AND on 11010 and 111 leaves 10 (in binary) +or 2 (in decimal) as the result. +*********************************************************************************/ \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 3/Soln3_04.cpp b/9781484200087_Exercise_Solutions/Chapter 3/Soln3_04.cpp new file mode 100644 index 0000000..0f1b5b9 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 3/Soln3_04.cpp @@ -0,0 +1,43 @@ +// Exercise 3.4 Packing and unpacking characters. + +#include +#include + +int main() +{ + unsigned int packed {}; + unsigned char ch {}; + std::cout << std::left << std::setw(26) << "Enter a character: "; + std::cin >> ch; + packed |= ch; + + std::cout << std::setw(26) << "Enter a second character: "; + std::cin >> ch; + packed <<= 8; // Shift left 1 byte + packed |= ch; + + std::cout << std::setw(26) << "Enter a third character: "; + std::cin >> ch; + packed <<= 8; // Shift left 1 byte + packed |= ch; + + std::cout << std::setw(26) << "Enter a fourth character: "; + std::cin >> ch; + packed <<= 8; // Shift left 1 byte + packed |= ch; + + std::cout << "The word containing 4 packed characters is " << std::right + << std::hex << std::showbase << std::internal << std::setfill('0') << packed << std::endl; + + // Unpacking packed... + unsigned int mask {0x000000FF}; // Keep low order byte + ch = mask & packed; // Low order byte + std::cout << std::setfill(' ') << std::setw(4) << ch; + + ch = mask & (packed >> 8); // 2nd byte + std::cout << std::setw(4) << ch; + ch = mask & (packed >> 16); + std::cout << std::setw(4) << ch; + ch = mask & (packed >> 24); // 4th byte + std::cout << std::setw(4) << ch << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 3/Soln3_05.cpp b/9781484200087_Exercise_Solutions/Chapter 3/Soln3_05.cpp new file mode 100644 index 0000000..ed166bb --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 3/Soln3_05.cpp @@ -0,0 +1,15 @@ +// Exercise 3.5 Swapping integers. + +#include + +int main() +{ + int first {}, second {}; + std::cout << "Enter two integers separated by a space: "; + std::cin >> first >> second; + + first ^= second; + second ^= first; + first ^= second; + std::cout << "In reverse order they are " << first << " and " << second << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 3/Soln3_06.cpp b/9781484200087_Exercise_Solutions/Chapter 3/Soln3_06.cpp new file mode 100644 index 0000000..52838b1 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 3/Soln3_06.cpp @@ -0,0 +1,34 @@ +// Exercise 3.6 Using an enumeration type for colors. +// Of course, you have to research the RBG components for the colors. + +#include +#include + +int main() +{ + const unsigned int R {0x00FF0000}; + const unsigned int G {0x0000FF00}; + const unsigned int B {0x000000FF}; + enum class Color :unsigned int{ Red = R, Green = G, Yellow = R | G, Purple = R | B, Blue = B, Black = 0, White = R | G | B }; + + Color color1 {Color::Yellow}; + Color color2 {Color::Purple}; + Color color3 {Color::Green}; + unsigned int color {static_cast(color1)}; // Get the enumerator value + std::cout << std::setw(38) << "The components of color1 (yellow) are:" + << " Red:" << std::setw(3) << ((color & R) >> 16) + << " Green:" << std::setw(3) << ((color & G) >> 8) + << " Blue:" << std::setw(3) << (color & B) << std::endl; + + color = static_cast(color2); + std::cout << std::setw(38) << "The components of color2 (purple) are:" + << " Red:" << std::setw(3) << ((color & R) >> 16) + << " Green:" << std::setw(3) << ((color & G) >> 8) + << " Blue:" << std::setw(3) << (color & B) << std::endl; + + color = static_cast(color3); + std::cout << std::setw(38) << "The components of color3 (green) are:" + << " Red:" << std::setw(3) << ((color & R) >> 16) + << " Green:" << std::setw(3) << ((color & G) >> 8) + << " Blue:" << std::setw(3) << (color & B) << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 4/Ex4_01.cpp b/9781484200087_Exercise_Solutions/Chapter 4/Ex4_01.cpp new file mode 100644 index 0000000..84a8135 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 4/Ex4_01.cpp @@ -0,0 +1,52 @@ +// Exercise 4.1 Testing for exact division of one integer by another. +// We can use an if statement to check that the input is valid +// and we can use another to arrange the input as we need. +// Then we use an if-else to generate the appropriate output. + +#include +using std::cin; +using std::cout; +using std::endl; + +int main() { + int value1 = 0; + int value2 = 0; + int remainder = 0; + + cout << "Please input two positive integers, separated by a space: "; + cin >> value1 >> value2; + cout << endl; + + if((value1 <= 0) || (value2 <= 0)) { // Valid input? + cout << "Sorry - positive integers only." << endl; + return 1; + } + + if(value1 < value2) { // Ensure that value1 is not smaller than value2 + int temp = value1; // ... swap if necessary + value1 = value2; + value2 = temp; + } + + /********************************************* + Note that we could write the if statement above as: + + if(value1 +using std::cin; +using std::cout; +using std::endl; +int main() { + int value = 0; + + cout << "Please enter an integer between 1 and 100: "; + cin >> value; + cout << endl; + + if ((value >= 1) && (value <= 100)) { + if (value > 50) + cout << "The integer is greater than 50." << endl; + else if (value < 50) + cout << "The integer is less than 50." << endl; + else + cout << "The integer you entered is 50." << endl; + } + else + cout << "The integer is not between 1 and 100." << endl; + + return 0; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 4/Ex4_03.cpp b/9781484200087_Exercise_Solutions/Chapter 4/Ex4_03.cpp new file mode 100644 index 0000000..1d56ef5 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 4/Ex4_03.cpp @@ -0,0 +1,50 @@ +// Exercise 4.3 Outputting the binary code for a letter. +/****************************************************************************************** + * The program is fairly simple. The cctype functions make determining upper or lower * + * case easy. Finding out if it's a vowel is also easy with a switch. Getting the binary * + * code needs a little thought. * + * Each of the masks selects a different bit of the ch variable. * + * If the bit is '1', the expression will be non-zero, which is converted to Boolean true.* + * If it's '0', the whole expression will be zero, or Boolean false. * + * Ones and zeros are therefore output as appropriate. * + ******************************************************************************************/ +#include +#include +using std::cin; +using std::cout; +using std::endl; + +int main() { + char ch = 0; + cout << "Enter a letter: "; + cin >> ch; + + if(!std::isalpha(ch)) { + cout << "That's not a letter!" << endl; + return 1; + } + + // Determine upper or lower case. + cout << "\'" << ch << "\' is " << (std::islower(ch) ? "lowercase.":"uppercase.") << endl; + + // Determine whether it is a vowel or a consonant. + cout << "\'" << ch << "\' is a "; + switch(std::tolower(ch)) { + case 'a': case 'e': case 'i': case 'o': case 'u': + cout << "vowel."; + break; + default: + cout << "consonant."; + break; + } + + // Output the character code as binary + cout << endl << "The binary code for \'" << ch << "\' is " + << ((ch & 0x80) ? 1 : 0) << ((ch & 0x40) ? 1 : 0) + << ((ch & 0x20) ? 1 : 0) << ((ch & 0x10) ? 1 : 0) + << ((ch & 0x08) ? 1 : 0) << ((ch & 0x04) ? 1 : 0) + << ((ch & 0x02) ? 1 : 0) << ((ch & 0x01) ? 1 : 0) + << endl; + + return 0; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 4/Ex4_04.cpp b/9781484200087_Exercise_Solutions/Chapter 4/Ex4_04.cpp new file mode 100644 index 0000000..a3c6336 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 4/Ex4_04.cpp @@ -0,0 +1,22 @@ +// Exercise 4.4 Finding the range for an integer. +// This is just a question of bolting sufficent conditional operators together +// in an expression. + +#include +using std::cin; +using std::cout; +using std::endl; + +int main() { + int n = 0; + cout << "Enter an integer: "; + cin >> n; + + + cout << "The value is " + << (n<=20 ? "not greater than 20." : (n<=30 ? "greater than 20 and not greater than 30." : + (n<=100 ? "greater than 30 and not exceeding 100.": "greater than 100." ))) + << endl; + + return 0; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 4/Ex4_05.cpp b/9781484200087_Exercise_Solutions/Chapter 4/Ex4_05.cpp new file mode 100644 index 0000000..10c59a9 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 4/Ex4_05.cpp @@ -0,0 +1,56 @@ +// Exercise 4.5 Dividing a cash amount into quarters, nickels, dimes and cents. + +#include +using std::cin; +using std::cout; +using std::endl; + +int main() { + // Declare the constants + const int quarter = 25; + const int dime = 10; + const int nickel = 5; + + double amount = 0.0; + cout << endl << "Please enter a cash amount between 0 and 10 dollars: $"; + cin >> amount; + int amountInCents = 0; + + int quarters = 0; + int dimes = 0; + int nickels = 0; + int cents = 0; + + + if ((amount > 0.0) && (amount <= 10.0)) { + // Multiply dollar amount by 100 ($1 = 100 cents) + // We add 0.5 to compensate for errors in binary floating-point representation + amountInCents = amount * 100.0+0.5; + + // Find the number of quarters + quarters = amountInCents/quarter; + amountInCents %= quarter; // Get the remainder + + // Find the number of dimes + dimes = amountInCents / dime; + amountInCents %= dime; // Get the remainder + + // Find the number of nickels + nickels = amountInCents / nickel; + amountInCents %= nickel; // Get the remainder + + // Find the number of cents + cents = amountInCents; // The remainder is already in cents + + cout << endl + << "The dollar value $" << amount << " can be broken down into:" << endl + << quarters << " quarter" << ((1 == quarters) ? "," : "s,") << endl + << dimes << " dime" << ((1 == dimes) ? "," : "s,") << endl + << nickels << " nickel" << ((1 == nickels) ? "," : "s,") << endl + << cents << " cent" << ((1 == cents) ? "." : "s.") << endl; + } + else + cout << endl << "You did not enter a dollar amount between 0 and 10." << endl; + + return 0; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 5/Soln5_01.cpp b/9781484200087_Exercise_Solutions/Chapter 5/Soln5_01.cpp new file mode 100644 index 0000000..1d6429f --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 5/Soln5_01.cpp @@ -0,0 +1,11 @@ +// Exercise 5.1 Squaring odd numbers +#include +#include + +int main() { + int limit {}; + std::cout << "Enter the upper limit for squared odd numbers: "; + std::cin >> limit; + for (int i {1}; i <= limit; i += 2) + std::cout << std::setw(4) << i << " squared is " << std::setw(8) << i * i << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 5/Soln5_02.cpp b/9781484200087_Exercise_Solutions/Chapter 5/Soln5_02.cpp new file mode 100644 index 0000000..ad2e029 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 5/Soln5_02.cpp @@ -0,0 +1,28 @@ +// Exercise 5.2 Summing integers and calculating the average +#include +#include +#include + +int main() +{ + char ch {}; + int n {}; + int count {}; + long total {}; + std::cout << "Enter the the first integer: "; + while (true) + { + std::cin >> n; + total += n; + ++count; + std::cout << "Do you want to enter another(y/n)?"; + std::cin >> ch; + if (std::tolower(ch) == 'n') + break; + else + std::cout << "Enter an integer: "; + } + std::cout << "The total is " << total << std::endl + << "The average is " << std::setw(10) << std::setprecision(2) + << std::fixed << (static_cast(total) / count) << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 5/Soln5_03.cpp b/9781484200087_Exercise_Solutions/Chapter 5/Soln5_03.cpp new file mode 100644 index 0000000..7d240a8 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 5/Soln5_03.cpp @@ -0,0 +1,21 @@ +// Exercise 5.3 Using a do-while loop to count characters +#include + +int main() +{ + long count {}; + char ch {}; + + std::cout << "Please enter a sequence of characters terminated by '#':" << std::endl; + + // We have to read at least one character - even if it's '#' - so do-while is best + do { + std::cin >> ch; + ++count; + } while (ch != '#'); + + // We do not count '#' as a character, so count must be adjusted + --count; + std::cout << "You entered " << count + << " characters (not counting spaces and the terminal #)." << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 5/Soln5_04.cpp b/9781484200087_Exercise_Solutions/Chapter 5/Soln5_04.cpp new file mode 100644 index 0000000..ff01df9 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 5/Soln5_04.cpp @@ -0,0 +1,22 @@ +// Exercise 5.4 Working with a vector container +#include +#include +#include + +int main() +{ + std::vector values; + // Add element values 1 to 100 + for (int i {1}; i <= 100; ++i) + values.push_back(i); + + size_t count {}; // Number of output values + size_t perline {8}; // Number output perline + for (auto value : values) + { + if ((value % 7) == 0 || (value % 13) == 0) continue; + std::cout << std::setw(5) << value; + if ((++count % perline) == 0) std::cout << "\n"; + } + std::cout << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 5/Soln5_05.cpp b/9781484200087_Exercise_Solutions/Chapter 5/Soln5_05.cpp new file mode 100644 index 0000000..121b303 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 5/Soln5_05.cpp @@ -0,0 +1,48 @@ +// Exercise 5.5 Outputting product records & cost +// Getting the alignment right is tricky. +// You have to adjust the field widths until it looks OK. +#include +#include +#include +#include +using std::setw; + +int main() +{ + std::vector product_id; + std::vector quantity; + std::vector unit_cost; + + // Read the records + size_t id {}; + size_t n {}; + double cost {}; + char answer {}; + + // Read the records + while (true) + { + std::cout << "Enter a record - product number, quantity, unit cost separated by spaces: "; + std::cin >> id >> n >> cost; + product_id.push_back(id); + quantity.push_back(n); + unit_cost.push_back(cost); + std::cout << "Do you want to enter another record (Y or N): "; + std::cin >> answer; + if (std::toupper(answer) == 'N') break; + } + // Column headings + std::cout << setw(10) << "Product" << setw(10) << "Quantity" << setw(12) << "Unit Price" << setw(14) << "Cost\n"; + double total_cost {}; + for (size_t i {}; i < product_id.size(); ++i) + { + std::cout << std::setw(8) << product_id[i] + << std::setw(8) << quantity[i] + << std::setw(9) << "$" << std::fixed << std::setprecision(2) << setw(5) << unit_cost[i]; + cost = quantity[i] * unit_cost[i]; + total_cost += cost; + std::cout << std::setw(10) << "$" << std::fixed << std::setprecision(2) << setw(5) << cost << std::endl; + } + std::cout << std::setw(40) << "$" << std::fixed << std::setprecision(2) << setw(5) << total_cost << std::endl; + +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 5/Soln5_06.cpp b/9781484200087_Exercise_Solutions/Chapter 5/Soln5_06.cpp new file mode 100644 index 0000000..b9070b9 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 5/Soln5_06.cpp @@ -0,0 +1,26 @@ +// 90 was not an arbitrary choice for the number of Fibonacci numbers. +// Fibonacci number grow very rapidly. +// 90 is around the most that are possible with type unsigned long long. + +#include +#include +#include +using std::setw; + +int main() +{ + const size_t n {90}; + std::array fib; + fib[0] = fib[1] = 1UL; + for (size_t i {2}; i < n; ++i) + fib[i] = fib[i - 1] + fib[i - 2]; + + std::cout << "The first " << n << " Fibonacci numbers are:\n"; + const size_t perline {5}; + size_t count {}; + for (auto number : fib) + { + std::cout << setw(22) << number; + if (++count % perline == 0) std::cout << std::endl; + } +} diff --git a/9781484200087_Exercise_Solutions/Chapter 6/Soln6_01.cpp b/9781484200087_Exercise_Solutions/Chapter 6/Soln6_01.cpp new file mode 100644 index 0000000..6ea7564 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 6/Soln6_01.cpp @@ -0,0 +1,28 @@ +// Exercise 6.1 Storing even numbers in an array and accessing them using pointer notation +#include +#include + +int main() +{ + const size_t n {50}; + size_t evens[n]; + for (size_t i {}; i < n; ++i) + evens[i] = 2 * (i + 1); + + const size_t perline {10}; + std::cout << "The numbers are:\n"; + for (size_t i {}; i < n; ++i) + { + std::cout << std::setw(5) << *(evens + i); + if ((i + 1) % perline) continue; // Uses the loop counter to decide when a newline is required + std::cout << std::endl; + } + + std::cout << "\nIn reverse order the numbers are:\n"; + for (int i {n - 1}; i >= 0; --i) // This won't work with size_t for the loop counter + { // because size_t cannot be negative + std::cout << std::setw(5) << *(evens + i); + if (i % perline) continue; + std::cout << std::endl; + } +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 6/Soln6_02.cpp b/9781484200087_Exercise_Solutions/Chapter 6/Soln6_02.cpp new file mode 100644 index 0000000..45a933f --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 6/Soln6_02.cpp @@ -0,0 +1,22 @@ +// Exercise 6.2 Storing numbers in a dynamic array +// This will only work for modest values for the array size. +// See the dsolution to Exercise 6.3 for an explanation why. +#include +#include + +int main() +{ + size_t n {}; + std::cout << "Enter the number of array elements: "; + std::cin >> n; + auto values = new (double[n]); + for (size_t i {}; i < n; ++i) + *(values+i) = 1.0 / ((i + 1)*(i + 1)); + + double sum {}; + for (size_t i {}; i < n; ++i) + sum += *(values + i); + + std::cout << "result is " << std::sqrt(6.0*sum) << std::endl; + delete[] values; // Don't forget to free the memory! +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 6/Soln6_03.cpp b/9781484200087_Exercise_Solutions/Chapter 6/Soln6_03.cpp new file mode 100644 index 0000000..5c2a5c8 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 6/Soln6_03.cpp @@ -0,0 +1,26 @@ +// Exercise 6.3 Storing numbers in a vector +// The result is an approximate value for pi. +// We must dereference values to use it with the subscript operator +// because it is not a vector but a pointer to a vector. +#include +#include +#include + +int main() +{ + size_t n {}; + std::cout << "Enter the number of vector elements: "; + std::cin >> n; + auto values = new std::vector(n); + // If you use size_t as the type for the loop counter, the expression (i+1)*(i+1) + // will produce an incorrect result for large value of i because the result will exceed the macximum for the type. + // The index for the vector has to be size_t, and the explicit cast avoids a warning from the compiler. + for (unsigned long long i {}; i < n; ++i) + (*values)[static_cast(i)] = 1.0 / ((i + 1)*(i + 1)); + double sum {}; + for (auto value : *(values)) + sum += value; + + std::cout << "Result is " << std::sqrt(6.0*sum) << std::endl; + delete values; // It's not an array this time! +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 6/Soln6_04.cpp b/9781484200087_Exercise_Solutions/Chapter 6/Soln6_04.cpp new file mode 100644 index 0000000..284671b --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 6/Soln6_04.cpp @@ -0,0 +1,40 @@ +// Exercise 6.4 Using an array of pointers to arrays. +// This is essentially an exercise in allocating heap memory using new. +#include +#include +#include + +int main() +{ + const size_t n_arrays {3}; // Number of arrays + const size_t dimension {6}; // Dimension of each array + auto arrays = new int*[n_arrays]; + for (size_t i {}; i < n_arrays; ++i) + arrays[i] = new int[dimension]; + + size_t value {}; + for (size_t j {}; j < dimension; ++j) + { + value = j + 1; + for (size_t i {}; i < n_arrays; ++i) + { + arrays[i][j] = std::pow(value, i + 1); + } + } + + std::cout << "The values in the arrays are:\n"; + for (size_t i {}; i < n_arrays; ++i) + { + for (size_t j {}; j < dimension; ++j) + { + std::cout << std::setw(5) << arrays[i][j]; + } + std::cout << std::endl; + } + + // Now free the memory... + for (size_t i {}; i < n_arrays; ++i) + delete[] arrays[i]; // First the arrays... + + delete[] arrays; // ...then the array of pointers. +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 6/Soln6_05.cpp b/9781484200087_Exercise_Solutions/Chapter 6/Soln6_05.cpp new file mode 100644 index 0000000..01dda55 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 6/Soln6_05.cpp @@ -0,0 +1,53 @@ +// Exercise 6.5 Storing student ages in dynamic array containers +// This tests how well you manage to separate different levels of pointers. +// Because we use smart pointers, releasing free store memory is taken care of automatically. +// I used some type aliases to make the code a bit clearer. + +#include +#include +#include +#include +#include +using Class = std::vector; // Type alias for vector storing the ages for student in a class +using PClass = std::shared_ptr; // Type alias for a smart pointer to a Class +using PClasses = std::vector; // Type alias for a vector of pointers to Class objects + +int main() +{ + auto pclasses = std::make_shared (); // Pointer to vector of pointers to Class objects + size_t age {}; + PClass pclass; + char answer {}; + while (true) + { + pclass = std::make_shared(); + pclasses->push_back(pclass); + + std::cout << "Enter ages for the class, enter 0 to end:\n"; + while (true) + { + std::cin >> age; + if (!age) break; + pclass->push_back(age); + } + std::cout << "Do you want to enter ages for another class(Y or N): "; + std::cin >> answer; + if (std::toupper(answer) == 'N') break; + } + + const size_t perline {5}; + size_t count {}; + size_t class_id {}; + for (auto& pclass : *pclasses) + { + count = 0; + std::cout << "\nAges of student in class " << ++class_id << ":\n"; + for (auto age : *pclass) + { + std::cout << std::setw(5) << age; + if (++count % perline) continue; + std::cout << std::endl; + } + std::cout << std::endl; + } +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 7/Soln7_01.cpp b/9781484200087_Exercise_Solutions/Chapter 7/Soln7_01.cpp new file mode 100644 index 0000000..01c45ea --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 7/Soln7_01.cpp @@ -0,0 +1,57 @@ +// Exercise 7.1 Storing student names and grades. +// This uses a vector of string objects to store the names. +#include +#include +#include +#include +#include +using std::string; + +int main() +{ + + std::vector names; + std::vector grades; + double average_grade {}; + char answer {}; + + // Data entry loop. This loop reads the name and grade for each student. + string name; // Stores a student name + size_t max_length {}; // Longest name length + double grade {}; // Stores a student grade + while(true) + { + std::cout << "Enter a student's name: "; + std::cin >> name; + names.push_back(name); + if (max_length < name.length()) max_length = name.length(); + + std::cout << "Enter " << name << "\'s grade: "; + std::cin >> grade; + grades.push_back(grade); + + average_grade += grade; + + std::cout << "Do you wish to enter another student's details (y/n): "; + std::cin >> answer; + if (std::toupper(answer) == 'N') break; + } + + // Calculating the class average. + average_grade /= grades.size(); + + // Displaying the class average. + std::cout << "\nThe class average for " << names.size() << " students is " + << std::fixed << std::setprecision(2) << average_grade << std::endl; + + // Displaying the students' names and grades. + const size_t perline {3}; + for (size_t i {}; i < names.size(); ++i) + { + std::cout << " " << std::left << std::setw(max_length) << names[i] + << std::right << std::setw(6) << std::setprecision(2) << grades[i]; + if ((i + 1) % perline) continue; + std::cout << std::endl; + } + std::cout << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 7/Soln7_02.cpp b/9781484200087_Exercise_Solutions/Chapter 7/Soln7_02.cpp new file mode 100644 index 0000000..be2c531 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 7/Soln7_02.cpp @@ -0,0 +1,63 @@ +// Exercise 7.2 Frequency of words in text. +#include +#include +#include +#include +using std::string; + +int main() +{ + string text; // The text to be searched + std::cout << "Enter some text terminated by *:\n"; + std::getline(std::cin, text, '*'); + + const string separators {" ,;:.\"!?'\n"}; // Word delimiters + std::vector words; // Words found + std::vector counts; // Words found + + size_t start {text.find_first_not_of(separators)}; // First word start index + size_t end {}; // Index for end of a word + string word; // Stores a word + bool is_in {false}; + while (start != string::npos) // Find the words + { + end = text.find_first_of(separators, start + 1); // Find end of word + if (end == string::npos) // Found a separator? + end = text.length(); // No, so set to last + 1 + word = text.substr(start, end - start); // Record the word + + // Check for word already in vector + is_in = false; // true when word has been found before + for (int i {}; i < words.size(); ++i) + { + if (words[i] == word) + { + ++counts[i]; + is_in = true; + break; + } + } + if (!is_in) // If it's a new word... + { + words.push_back(word); // ...store the word... + counts.push_back(1); // ...and record the count + } + start = text.find_first_not_of(separators, end + 1); // Find 1st character of next word + } + + // Find maximum word length + size_t max_length {}; + for (auto& word : words) + if (max_length < word.length()) max_length = word.length(); + + std::cout << "Your string contains the following " << words.size() << " words and counts:\n"; + size_t count {}; // Numbers of words output + const size_t perline {3}; // Number per line + for (size_t i {}; i < words.size(); ++i) + { + std::cout << std::setw(max_length) << std::left << words[i] << std::setw(4) << std::right << counts[i] << " "; + if (!(++count % perline)) + std::cout << std::endl; + } + std::cout << std::endl; +} diff --git a/9781484200087_Exercise_Solutions/Chapter 7/Soln7_03.cpp b/9781484200087_Exercise_Solutions/Chapter 7/Soln7_03.cpp new file mode 100644 index 0000000..7d144ab --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 7/Soln7_03.cpp @@ -0,0 +1,53 @@ +// Exercise 7.3 Replacing a word in text by asterisks. +// Because we are looking for the word regardless of case, +// the best way is to scan the text character by character. +#include +#include +#include +using std::string; + +int main() +{ + string text; // The text to be searched + string word; // Stores the word to be replaced + char asterisk {'*'}; + std::cout << "Enter some text terminated by *:\n"; + std::getline(std::cin, text, '*'); + std::cout << "\nEnter the word to be replaced: "; + std::cin >> word; + string uc_word {word}; + for (auto& ch : uc_word) + ch = std::toupper(ch); + + + + const string separators {" ,;:.\"!?'\n"}; // Word delimiters + + size_t start {text.find_first_not_of(separators)}; // First word start index + size_t end {}; // Index for end of a word + bool is_word {false}; // true when word is found + while (start != string::npos) // Find the words + { + end = text.find_first_of(separators, start + 1); // Find end of word + if (end == string::npos) // Found a separator? + end = text.length(); // No, so set to last + 1 + + // Compare the word found in uppercase with uc_word + if (end - start == word.length()) + { + is_word = true; // Assume it is the word + for (size_t i {start}; i < end; ++i) + if (uc_word[i - start] != toupper(text[i])) // If a character differs... + { + is_word = false; // ...it is not the word + break; + } + if (is_word) // If it is the word... + for (size_t i {start}; i < end; ++i) // ... replace by asterisks + text[i] = asterisk; + } + start = text.find_first_not_of(separators, end + 1); // Find 1st character of next word + } + + std::cout << std::endl << text << std::endl; +} diff --git a/9781484200087_Exercise_Solutions/Chapter 7/Soln7_04.cpp b/9781484200087_Exercise_Solutions/Chapter 7/Soln7_04.cpp new file mode 100644 index 0000000..5d7528b --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 7/Soln7_04.cpp @@ -0,0 +1,43 @@ +// Exercise 7.4 Check for anagrams. +// There's more than one way to do this. +// I chose to delete characters in one word that are common to both. +// If the length of thw word that has characters deleted is zero, they are anagrams. +#include +#include +#include +using std::string; + +int main() +{ + string word1; + string word2; + + std::cout << "Enter the first word: "; + std::cin >> word1; + std::cout << "Enter the second word: "; + std::cin >> word2; + + // Test the pathological case of the strings being different lengths + if (word1.length() != word2.length()) { + std::cout << word1 << " and " << word2 << " are different lengths so they can't be anagrams!" << std::endl; + return 0; + } + + string word2_copy {word2}; // Copy word2 - because we will delete characters + // Loop over all the characters in word1 + for (size_t i {}; i < word1.length(); ++i) + { + // Loop over all the characters in word2 + for (size_t j {}; j < word2_copy.length(); j++) + if (std::tolower(word2_copy[j]) == std::tolower(word1[i])) + { + word2_copy.erase(j, 1); // Character found so erase from word2 + break; + } + } + + std::cout << word1 << " and " << word2 << " are " + << (word2_copy.length() ? "not" : "") + << " anagrams of one another." + << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 7/Soln7_05.cpp b/9781484200087_Exercise_Solutions/Chapter 7/Soln7_05.cpp new file mode 100644 index 0000000..f050093 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 7/Soln7_05.cpp @@ -0,0 +1,60 @@ +// Exercise 7.5 Finding words that begin with a given letter. +// If you wanted the words ordered by the first letter, you could sort the contents of letter first. +// You could also retain all the sets of words for each letter in a separate vector for each set. +// Of course, you don't know how many sets will be required. +// You could accommodate this by creating a vector of smart pointers to the vectors to contain the words, +// then use std::make_shared() to create a vector for each starting letter and store its address in the vector of pointers. +#include +#include +#include +#include +#include +using std::string; + +int main() +{ + string text; // The text to be searched + string letters; + std::cout << "Enter some text terminated by *:\n"; + std::getline(std::cin, text, '*'); + std::cout << "\nEnter the starting letters for the words you want to find: "; + std::cin >> letters; + + const string separators {" ,;:.\"!?'\n"}; // Word delimiters + std::vector words; // Words found + const size_t perline {5}; // Words output per line + size_t count {}; // Number of words found + for (auto ch : letters) + { + size_t start {text.find_first_not_of(separators)}; // First word start index + size_t end {}; // Index for end of a word + string word; // Stores a word + size_t max_length {}; // Maximum word length + while (start != string::npos) // Find the words + { + end = text.find_first_of(separators, start + 1); // Find end of word + if (end == string::npos) // Found a separator? + end = text.length(); // No, so set to last + 1 + word = text.substr(start, end - start); // Record the word + if (std::toupper(word[0]) == std::toupper(ch)) // If it begins with the current letter... + { + words.push_back(word); // ...save the word + if (max_length < word.length()) max_length = word.length(); + } + + start = text.find_first_not_of(separators, end + 1); // Find 1st character of next word + } + // List words for current letter + max_length += 2; + std::cout << "\nWords beginning with '" << ch << "' are:\n"; + for (auto& word : words) + { + std::cout << std::setw(max_length) << std::left << word; + if (++count % perline) continue; + std::cout << std::endl; + } + std::cout << std::endl; + words.clear(); + count = 0; + } +} diff --git a/9781484200087_Exercise_Solutions/Chapter 8/Soln8_01.cpp b/9781484200087_Exercise_Solutions/Chapter 8/Soln8_01.cpp new file mode 100644 index 0000000..12cb495 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 8/Soln8_01.cpp @@ -0,0 +1,93 @@ +// Exercise 8.1 Reading and validating a date of birth. +// As always, there are many ways of doing this so this is not the only solution +// or even the best solution! +#include +#include +using std::string; + +int validate_input(int lower, int upper, const string& description); +int year(); +int month(); +int date(int month_value, int year_value); +string ending(int date_day); + + +int main() +{ + std::cout << "Enter your date of birth." << std::endl; + int date_year {year()}; + int date_month {month()}; + int date_day {date(date_month, date_year)}; + + string months[] {"January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" }; + + std::cout << std::endl + << "We have established that your were born on " + << months[date_month - 1] << " " << date_day << ending(date_day) + << ", " << date_year << "." << std::endl; +} + +// Reads an integer that is between lower and upper inclusive +int validate_input(int lower, int upper, const string& description) +{ + int data {}; + std::cout << "Please enter " << description << " from " << lower << " to " << upper << ": "; + std::cin >> data; + while (data < lower || data > upper) + { + std::cout << "Invalid entry; please re-enter " << description << ": "; + std::cin >> data; + } + return data; +} + + +// Reads the year +int year() +{ + const int low_year {1864}; // Program only works for folks under 150 years old + const int high_year {2012}; // and over 2 years old... + return validate_input(low_year, high_year, "a year"); +} + +// Reads the month +int month() +{ + const int low_month {1}; + const int high_month {12}; + return validate_input(low_month, high_month, "a month number"); +} + +// Reads in the date in the given month and year +int date(int month_number, int year) +{ + const int date_min {1}; + const int feb {2}; + + // Days in month: Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec + static const int date_max[] {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + // With the above array declared as static, it will only be created the first + // time the function is called. Of course, this doesn't save anything in this + // example as we only call it once... + + // Feb has 29 days in a leap year. A leap year is a year that is divible by 4 + // except years that are divisible by 100 but not divisible by 400 + if (month_number == feb && year % 4 == 0 && !(year % 100 == 0 && year % 400 != 0)) + return validate_input(date_min, date_max[month_number - 1] + 1, "a date"); + else + return validate_input(date_min, date_max[month_number - 1], "a date"); +} + +// Select day day ending +inline string ending(int date_day) +{ + if (date_day == 1 || date_day == 21 || date_day == 31) + return "st"; + else if (date_day == 2 || date_day == 22) + return "nd"; + else if (date_day == 3 || date_day == 23) + return "rd"; + else + return "th"; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 8/Soln8_02.cpp b/9781484200087_Exercise_Solutions/Chapter 8/Soln8_02.cpp new file mode 100644 index 0000000..1155faa --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 8/Soln8_02.cpp @@ -0,0 +1,43 @@ +// Exercise 8.2 Reversing the order of a string of characters. +/****************************************************************** +The reverse() function works with an argument of type string, or a +C-style string terminated with '\0'. +*******************************************************************/ +#include +#include +using std::string; + +string reverse(string str1); + +int main() +{ + string sentence; + std::cout << "Enter a sequence of characters, then press 'Enter': " << std::endl; + getline(std::cin, sentence); + + std::cout << std::endl + << "Your sequence in reverse order is:\n"; + std::cout << reverse(sentence) << std::endl; + + std::cout << "Here is a demonstration of reverse() working with a C-style string:\n"; + + char stuff[] {"abcdefg"}; // C-style string + std::cout << std::endl << "The original string is: \"" << stuff << "\"" << std::endl + << "Reversed it becomes: \"" << reverse(stuff) << "\"" << std::endl; +} + +// Reverse a string in place +// The code here is working with a copy of the argument +// so the original is not affected. +string reverse(string str) +{ + char temp {}; + size_t len {str.length()}; + for (size_t i {}; i < str.length() / 2; ++i) + { + temp = str[i]; + str[i] = str[len - i - 1]; + str[len - i - 1] = temp; + } + return str; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 8/Soln8_03.cpp b/9781484200087_Exercise_Solutions/Chapter 8/Soln8_03.cpp new file mode 100644 index 0000000..b625e1b --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 8/Soln8_03.cpp @@ -0,0 +1,16 @@ +// Exercise 8.3 Checking the number of arguments entered at the command line. +#include + +int main(int argc, char* argv[]) +{ + switch (argc - 1) + { + case 2: case 3: case 4: + for (size_t i {1}; i < argc; ++i) + std::cout << "Argument " << i << " is " << argv[i] << std::endl; + break; + default: + std::cout << "You entered the incorrect number of arguments.\n" + << "Please enter 2, 3 or 4 arguments. " << std::endl; + } +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 8/Soln8_04.cpp b/9781484200087_Exercise_Solutions/Chapter 8/Soln8_04.cpp new file mode 100644 index 0000000..018f438 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 8/Soln8_04.cpp @@ -0,0 +1,52 @@ +// Exercise 8.4 An overloaded plus() function. +#include +#include +using std::string; +int plus(int a, int b); +double plus(double x, double y); +string plus(string s1, string s2); + +int main() +{ + int n {plus(3, 4)}; + std::cout << "plus(3, 4) returns " << n << std::endl; + double d {plus(3.2, 4.2)}; + std::cout << "plus(3.2, 4.2) returns " << d << std::endl; + string s {plus("he", "llo")}; + std::cout << "plus(\"he\", \"llo\") returns " << s << std::endl; + string s1 {"aaa"}; + string s2 {"bbb"}; + string s3 {plus(s1, s2)}; + std::cout << "With s1 as " << s1 << " and s2 as " << s2 << std::endl; + + std::cout << "plus(s1, s2) returns " << s3 << std::endl; + + /* + int d {plus(3, 4.2); + This won't compile because there is more than one overloaded plus() function for the arguments. + The compiler will not choose so there must be a unique match with a function signature. + + */ +} + + +// Adding integer values +inline int plus(int a, int b) +{ + return a + b; +} + +// Adding floating-point values +inline double plus(double x, double y) +{ + return x + y; +} + +// Adding strings +inline string plus(string s1, string s2) +{ + return s1 + s2; +} + + + diff --git a/9781484200087_Exercise_Solutions/Chapter 8/Soln8_05.cpp b/9781484200087_Exercise_Solutions/Chapter 8/Soln8_05.cpp new file mode 100644 index 0000000..a7c320d --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 8/Soln8_05.cpp @@ -0,0 +1,45 @@ +// Exercise 8.5 Generating Fibonacci numbers using two functions. +//Once you have updated the smaller of val1 and val2, it then becomes the larger! +#include +#include +using std::cout; +using std::cin; +using std::endl; + +long& smaller(long& m, long& n); +long& larger(long& m, long& n); + + +int main() +{ + int count {}; + cout << "How many values in the Fibonacci sequence would you like? "; + std::cin >> count; + + long n1 {1L}; // First in sequence + long n2 {1L}; // Second in sequence + std::cout << std::endl << std::setw(15) << n1 << std::setw(15) << n2; + + for (size_t i {2}; i < count; ++i) + { + if (i % 5 == 0) + std::cout << std::endl; + smaller(n1, n2) = n1 + n2; + std::cout << std::setw(15) << larger(n1, n2); + } + std::cout << std::endl; +} + +// Returns the smaller of the two arguments as a reference +// This means this function can be used on the rhs of an assignment +long& smaller(long& m, long& n) +{ + return m < n ? m : n; +} + +// Returns the larger of the two arguments as a reference +// This means this function can be used on the rhs of an assignment +long& larger(long& m, long& n) +{ + return m > n ? m : n; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 8/Soln8_06.cpp b/9781484200087_Exercise_Solutions/Chapter 8/Soln8_06.cpp new file mode 100644 index 0000000..d3dd6e6 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 8/Soln8_06.cpp @@ -0,0 +1,48 @@ +// Exercise 8.6 A plus() function template. +// You can define a template specialization to allow plus() to be used with C-style strings. +// Note that you could not define a template specialization if the template parameters were not const. +// The type of a string literal is const char*. +// In that case you could define the overloaded function that is commented out below. +#include +#include +using std::string; + +template +T plus(const T a, const T b) +{ + return a + b; +} + +template <> +const char* plus(const char* a, const char* b) +{ + return (string {a} + b).c_str(); +} + +/* +This function definition could oveload the template to allow plus() to be called for C-style strings +const char* plus(const char* a, const char* b) +{ + return (string {a} +b).c_str(); +} +*/ + + +int main() +{ + int n {plus(3, 4)}; + std::cout << "plus(3, 4) returns " << n << std::endl; + double d {plus(3.2, 4.2)}; + std::cout << "plus(3.2, 4.2) returns " << d << std::endl; + string s {plus("he", "llo")}; + std::cout << "plus(\"he\", \"llo\") returns " << s << std::endl; + string s1 {"aaa"}; + string s2 {"bbb"}; + string s3 {plus(s1, s2)}; + std::cout << "With s1 as " << s1 << " and s2 as " << s2 << std::endl; + + std::cout << "plus(s1, s2) returns " << s3 << std::endl; +} + + + diff --git a/9781484200087_Exercise_Solutions/Chapter 8/Soln8_07.cpp b/9781484200087_Exercise_Solutions/Chapter 8/Soln8_07.cpp new file mode 100644 index 0000000..81bbf0c --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 8/Soln8_07.cpp @@ -0,0 +1,52 @@ +// Exercise 8.7 Computing Ackerman's function. + +#include +#include + +// Using unsigned long long provides the maximum possible range of values +// but is woefully inadequate for significant values of m and n. +unsigned long long ack(unsigned long long m, unsigned long long n); + +int main() +{ + size_t m {}; + size_t n {}; + std::cout << "Computing values of Ackerman's function - Ack(m,n):" << std::endl; + std::cout << "Enter the upper limit for m: "; + std::cin >> m; + std::cout << "Enter the upper limit for n: "; + std::cin >> n; + if (m>3 && n>0 || m>2 && n>9) + std::cout << "You are an optimist!" << std::endl; + + // Create array dynamically to hold values + unsigned long long** ack_values = new unsigned long long*[m + 1]; // Pointer to array of arrays of unsigned long long elements + for (size_t i = {}; i <= m; ++i) + ack_values[i] = new unsigned long long[n + 1]; + + // Store values in the array + for (size_t i = {}; i <= m; ++i) + for (size_t j = {}; j <= n; ++j) + ack_values[i][j] = ack(i, j); + + for (size_t i {}; i <= m; i++) + { + std::cout << std::endl; + for (size_t j {}; j <= n; ++j) + std::cout << std::setw(12) << ack_values[i][j]; + } + std::cout << std::endl; + + for (size_t i {}; i < m + 1; ++i) + delete[] ack_values[i]; + delete ack_values; +} + +unsigned long long ack(unsigned long long m, unsigned long long n) +{ + if (m == 0ULL) + return n + 1; + if (n == 0ULL) + return ack(m - 1, 1); + return ack(m - 1, ack(m, n - 1)); +} diff --git a/9781484200087_Exercise_Solutions/Chapter 8/Soln8_08.cpp b/9781484200087_Exercise_Solutions/Chapter 8/Soln8_08.cpp new file mode 100644 index 0000000..2d4eec5 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 8/Soln8_08.cpp @@ -0,0 +1,84 @@ +// Exercise 8.8 A Quicksort funtion template + +// The top level sort() template with one parameter calls the sort() template with three parameters +// The sort() function template uses the swap() function template +// The list() template outputs all elements in a vector. + +#include +#include +#include + +// Swap two vector elements +template +inline void swap(std::vector& data, size_t first, size_t second) +{ + T temp {data[first]}; + data[first] = data[second]; + data[second] = temp; +} + +// Sort a range of vector elements +template +void sort(std::vector& data, size_t start, size_t end) +{ + // start index must be less than end index for 2 or more elements + if (!(start < end)) + return; + + // Choose middle address to partition set + swap(data, start, (start + end) / 2); // Swap middle address with start + + // Check data against chosen value + size_t current {start}; + for (size_t i {start + 1}; i <= end; ++i) + { + if (data[i] < data[start]) // Is word less than chosen word? + swap(data, ++current, i); // Yes, so swap to the left + } + + swap(data, start, current); // Swap the chosen word with last in + + if (current > start) sort(data, start, current - 1); // Sort left subset if exists + if (end > current + 1) sort(data, current + 1, end); // Sort right subset if exists +} + +// Sort all vector elements +template +inline void sort(std::vector& values) +{ + sort(values, 0, values.size() - 1); +} + +// Output vector elements +template +void list(std::vector values, size_t width = 5) +{ + for (auto value : values) + std::cout << std::setw(width) << value; + std::cout << std::endl; +} + +int main() +{ + std::cout << "Integers to be sorted:\n"; + std::vector numbers {-2, 4, -5, 6, 10, -40, 56, 4, 67, 45}; + list(numbers); + sort(numbers); + std::cout << "\n Sorted integers:\n"; + list(numbers); + + std::cout << "\nCharacters to be sorted:\n"; + std::vector letters {'C', 'd', 'a', 'z', 't', 'S', 'p', 'm', 'D', 'f'}; + list(letters, 2); + sort(letters); + std::cout << "\n Sorted characters:\n"; + list(letters, 2); + + std::cout << "\nFloating-point values to be sorted:\n"; + std::vector values {-2.5, 1.4, -2.55, 6.3, 10.1, -40.5, 56.0, 4.7, 67.3, 45.0}; + list(values, 10); + sort(values); + std::cout << "\n Sorted floaating-point values:\n"; + list(values, 10); + +} diff --git a/9781484200087_Exercise_Solutions/Chapter 9/Soln9_01.cpp b/9781484200087_Exercise_Solutions/Chapter 9/Soln9_01.cpp new file mode 100644 index 0000000..a246661 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 9/Soln9_01.cpp @@ -0,0 +1,30 @@ +// Exercise 9.1 A lambda expression finding the largest even number in a vector +#include +#include +#include + +int main() +{ + std::vector numbers {1, 2, 4, 16, -4, 5, 6, 3, 23}; + std::cout << "Nunbers are:\n"; + for (auto n : numbers) + std::cout << std::setw(5) << n; + std::cout << std::endl; + auto largest_even = [](std::vector& v){ + int largest {}; + bool found {false}; + for (auto n : v) + if (!found && n % 2 == 0) + { + largest = n; + found = true; + } + else + { + if (found && n % 2 == 0 && largest < n) + largest = n; + } + return largest; }; + + std::cout << "Largest even number is " << largest_even(numbers) << std::endl; +} diff --git a/9781484200087_Exercise_Solutions/Chapter 9/Soln9_02.cpp b/9781484200087_Exercise_Solutions/Chapter 9/Soln9_02.cpp new file mode 100644 index 0000000..725d57a --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 9/Soln9_02.cpp @@ -0,0 +1,29 @@ +// Exercise 9.2 A lambda expression accessing a variable in the outer scope by reference +// This uses a lambda expression to scale vector elements but you could pass a +// lambda expression to modify() to transform elements in other ways. +#include +#include +#include + +// Function to modify vector elements using a lambda expression, fun +template +void modify(std::vector& values, F fun) +{ + for (auto& value : values) + fun(value); +} + +int main() +{ + std::vector numbers {1.5, 2.5, 4.5, 16.5, -4.5, 5.5, 6.5, 3.5, 23.5}; + std::cout << "Numbers are:\n"; + for (auto n : numbers) + std::cout << std::setw(5) << n; + std::cout << std::endl; + double scale {2.0}; + modify(numbers, [&scale](double& v){ v *= scale; }); + std::cout << "Numbers scaled by " << scale <<" are:\n"; + for (auto n : numbers) + std::cout << std::setw(5) << n; + std::cout << std::endl; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 9/Soln9_03.cpp b/9781484200087_Exercise_Solutions/Chapter 9/Soln9_03.cpp new file mode 100644 index 0000000..b51fe31 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 9/Soln9_03.cpp @@ -0,0 +1,26 @@ +// Exercise 9.3 A lambda expression returning the number of vector elements that begin with a given letter. +#include +#include +#include +#include +using std::string; + +int main() +{ + std::vector words {"apple", "pear", "plum", "orange", "peach", "grape", "greengage"}; + std::cout << "Words are:\n"; + for (auto word : words) + std::cout << std::setw(10) << word; + std::cout << std::endl; + + auto count = [&words](char letter){ + size_t n {}; + for (auto& word : words) + if (letter == word[0]) ++n; + return n; + }; + char ch {'p'}; + std::cout << "There are " << count(ch) << " words beginning with " << ch << ".\n"; + ch = 'g'; + std::cout << "There are " << count(ch) << " words beginning with " << ch << ".\n"; +} \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Chapter 9/Soln9_04.cpp b/9781484200087_Exercise_Solutions/Chapter 9/Soln9_04.cpp new file mode 100644 index 0000000..1f7ac85 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Chapter 9/Soln9_04.cpp @@ -0,0 +1,18 @@ +// Exercise 9.4 A recursive lambda expression +#include +#include + +int main() +{ + std::function reverseNumber {[&reverseNumber](size_t no) -> size_t + { + static size_t r {}; + if (0 == no) + return r; + else + r = r * 10 + no % 10; + return reverseNumber(no / 10); + }}; + int nn {12345}, r {}; + std::cout << nn << " " << reverseNumber(nn) << std::endl; +} diff --git a/9781484200087_Exercise_Solutions/Project/Project Code/Address.h b/9781484200087_Exercise_Solutions/Project/Project Code/Address.h new file mode 100644 index 0000000..6990288 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Project/Project Code/Address.h @@ -0,0 +1,107 @@ +// Encapsulate an address +/* +A US address consists of four parts: address(up to 3 lines), city, state, ZIP code(5 digits). +The ZIP code is verified to be 5 digits. +Input and output of an Address object is done using the >> and << operators. +Input from a stream that is not a file is prompted and the ZIP code is checked. +Input from a file stream is assumed to be correct. +*/ +#ifndef ADDRESS_H +#define ADDRESS_H + +#include +#include +using std::string; + +bool isInteger(string s); // Returns true if s contains only digits + +class Address +{ +protected: + string address; // Address - one or more lines + size_t line_count {}; // Number of lines in address + + string city; + string state; + string zip; + +public: + Address() = default; + + string get_address() const { return address; } + string get_city() const { return city; } + string get_state() const { return state; } + string get_zip() const { return zip; } + + // Friend I/O functions + friend std::istream& operator>>(std::istream& in, Address& name); + friend std::ostream& operator<<(std::ostream& out, Address& name); +}; + +inline std::istream& operator>>(std::istream& in, Address& addr) +{ + // If it's not file input, we need prompts and validation of the data + if (notFile(in)) + { + std::cout << "The address is one or more address lines followed by city, state, and zip code.\n"; + std::cout << "Enter one or more address lines followed by an empty line:\n"; + + in.ignore(); + string line; + while (true) + { + std::getline(in, line); + if (line.empty()) break; + addr.address += line + "\n"; + ++addr.line_count; + } + std::cout << "Enter the city:\n"; + std::getline(in, addr.city); + std::cout << "Enter the state:\n"; + std::getline(in, addr.state); + + std::cout << "Enter the ZIP code (5 digits):\n"; + while (true) + { + in >> addr.zip; + if (addr.zip.length() != 5) + { + std::cout << "ZIP code must be five digits. Try again.\n"; + continue; + } + if (!isInteger(addr.zip)) + { + std::cout << "ZIP code must be only numeric digits. Try again.\n"; + continue; + } + break; + } + return in; + } + + // It is a file so no prompts for input and the data is assumed to be OK + in >> addr.line_count; // Number of address lines + string line; + in >> std::skipws; + for (size_t i {}; i < addr.line_count; ++i) + { + getline(in, line); // Read a line + addr.address += line + "\n"; // Append the line and newline to address + } + + std::getline(in, addr.city); // Read the city + std::getline(in, addr.state); // Read the state + in >> addr.zip; // Read the zip code + return in; +} + +// Output to a stream +inline std::ostream& operator<<(std::ostream& out, Address& addr) +{ + if (isFile(out)) // If it's a file... + out << addr.line_count << " "; // ...write the line count + out << addr.address << addr.city << '\n' << addr.state << '\n' << addr.zip << std::endl; + return out; +} + +#endif \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Project/Project Code/Group.h b/9781484200087_Exercise_Solutions/Project/Project Code/Group.h new file mode 100644 index 0000000..e8bc6f7 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Project/Project Code/Group.h @@ -0,0 +1,106 @@ +// Template type to encapsulate person objects. +/* + A class template to store objects of type T in a vector. + Type T must be derived from Person. +*/ + +#ifndef GROUP_H +#define GROUP_H +#include +#include +#include +#include +#include "Person.h" + +using std::string; + +template class Group +{ + // Verify T is acceptable type + static_assert(std::is_base_of::value, "Group template only usable with types derived from Person."); +protected: + std::vector> people; // Contains pointers to the T objects + +public: + Group(size_t space = 20){ people.reserve(space); } + Group(const Group& people) = delete; // No copy contructor + Group& operator=(const Group& people) = delete; // No assignment operator + + void add(const T& person) // Add a person + { + people.push_back(std::shared_ptr(new T(person))); + } + + std::shared_ptr find(const string& second_name); // Find a person by name + bool remove(const string& second_name); // Remove a person by name + void clear(){ people.clear(); } // Remove all + std::ostream& put(std::ostream& out); // Output all +}; + +// Stream output operator for Group objects +template +inline std::ostream& operator<<(std::ostream& out, Group& group) +{ + return group.put(out); +} + +// Find a person by name +template +std::shared_ptr Group::find(const string& second_name) // Find a person by second name +{ + std::vector found_indexes; + for (size_t i {}; i < people.size(); ++i) + { + if (people.at(i)->getName().get_second_name() == second_name) + { + found_indexes.push_back(i); + } + } + if (found_indexes.size() == 0) + { + std::cout << second_name << " not found." << std::endl; + return nullptr; // Not found + } + if (found_indexes.size() == 1) return people.at(found_indexes[0]); // Found one + + // Found more than one... + std::cout << "Several people found with the name " << second_name << ". Choose from the following:\n"; + size_t index {}; + for (auto i : found_indexes) + { + std::cout << '[' << ++index << "] " << people.at(i)->getName() << std::endl; + } + std::cin >> index; + return people.at(found_indexes[index - 1]); +} + +// Remove a person by name +template bool Group::remove(const string& second_name) +{ + auto pperson = find(second_name); + if (!pperson) return false; + + for (size_t i {}; i < people.size(); ++i) + { + if (pperson == people.at(i)) + { + people.at(i) = people.back(); // Overwrite with last element to delete it + people.pop_back(); // Remove last element + return true; + } + } + return false; +} + +// Write a Group to a stream +template +std::ostream& Group::put(std::ostream& out) +{ + for (auto pperson : people) + { + pperson->put(out << std::endl); + } + + return out; +} +#endif diff --git a/9781484200087_Exercise_Solutions/Project/Project Code/Mainprog.cpp b/9781484200087_Exercise_Solutions/Project/Project Code/Mainprog.cpp new file mode 100644 index 0000000..7e4cc6c --- /dev/null +++ b/9781484200087_Exercise_Solutions/Project/Project Code/Mainprog.cpp @@ -0,0 +1,480 @@ +/* +*************************************************************** +* +* MainProg.cpp + This file includes the global functions for the program, + some of which are called by class members. + + It also define global variables that store the file paths + and variables that store the collections of students and teachers. + + There is no provision for entering file paths but this can be easily + implemented, either through command line entries or through + prompted input from the keyboard. +* +*************************************************************** +*/ + + +// standard library includes +#include +#include +#include +#include + +#include "Student.h" +#include "Teacher.h" +#include "Group.h" + +using std::string; + +// Global variables +Group students; // All students +Group teachers; // All teachers +static string students_file {"D:/Example_Data/students_file.txt"}; // Name and path for students file +static string teachers_file {"D:/Example_Data/teachers_file.txt"}; // Name and path for teachers file + +// Function Prototypes +void load_students(); // Loads Student objects from a file if it exists +void load_teachers(); // Loads Teacher objects from a file if it exists +bool isFile(std::ios& in); // Returns true if stream is a file +bool notFile(std::ios& in); // Returns true if not a file stream +bool isInteger(string s); // Returns true if s contains only digits +void display_records(); // Output all students or all teachers +char choose_person_type(); // Select a student or a teacher +void add_record(); // Add a student or a techer record +void delete_record(); // Delete a student or a teacher record +void delete_all_records(); // Delete all teachers or all students +void find_record(); // Find and display student or teacher record +void save_records(); // Save all student and teacher records to files + +/* +****************************************************** +* Function: main +* return: int +* parameters: none +* +* Description: +* Start of the program. This function will display +* the Main Menu. +* You could add paramters to allow optional specification +* of the file names to replace the defaults. +****************************************************** +*/ + +int main() +{ + load_students(); + load_teachers(); + char option {}; // User input + + while (true) + { + // Display the Main Menu + std::cout << std::endl << "MAIN MENU"; + std::cout << std::endl << "---------"; + std::cout << std::endl << "(A)dd a record"; + std::cout << std::endl << "(D)elete a record"; + std::cout << std::endl << "(C)lear a set of records"; + std::cout << std::endl << "(S)earch for a record"; + std::cout << std::endl << "Displa(Y) a set of records"; + std::cout << std::endl << "(Q)uit the Program" << std::endl; + std::cout << std::endl << "Enter Selection: "; + + std::cin >> option; + switch (std::toupper(option)) + { + case 'A': + // Add a record + add_record(); + break; + case 'D': + // Delete a record + delete_record(); + break; + case 'C': + // Delete all the records. + delete_all_records(); + break; + case 'S': + // Search for a record + find_record(); + break; + case 'Y': + // Display records + display_records(); + break; + case 'V': + // Save the records to disk + save_records(); + break; + case 'Q': + save_records(); + std::cout << "Ending the program." << std::endl; + return 0; + default: + std::cout << std::endl << "Invalid choice."; + break; + } + } +} + +/* +****************************************************** +* Function: load_students +* return: none +* parameters: none +* +* Description: +* Loads Student objects from the file identified by +* students_file if it exists. +****************************************************** +*/ +void load_students() +{ + std::cout << "Loading students...\n"; + Student student; + std::ifstream infile {students_file}; // Open the file to read it + if (infile.is_open()) // If it is open... + { // ...it exists, so read it + while (true) + { + infile >> student; // Read a student and... + if (!infile) break; + students.add(student); // ...add the student to the group. + } + infile.close(); + std::cout << "Students loaded from file." << std::endl; + } + else + std::cout << "No students from file." << std::endl; +} + +/* +****************************************************** +* Function: load_teachers +* return: none +* parameters: none +* +* Description: +* Loads Teacher objects from the file identified by +* teachers_file if it exists. +****************************************************** +*/ +void load_teachers() +{ + std::cout << "Loading teachers...\n"; + Teacher teacher; + std::ifstream infile {teachers_file}; // Open the file to read it + if (infile.is_open()) // If it is open... + { // ...it exists, so read it + while (true) + { + infile >> teacher; // Read a teacher and... + if (infile.eof()) break; + teachers.add(teacher); // ...add the teacher to the group. + } + std::cout << "Teachers loaded from file." << std::endl; + infile.close(); + } + else + std::cout << "No teachers from file." << std::endl; +} + +/****************************************************** +* Function: isFile +* return: bool +* parameters: std::ios (base for all stream classes) +* +* Description: +* Returns true if the argument is a file input stream. +* Used to decide when to prompt for stream input. +******************************************************/ +bool isFile(std::ios& stream) +{ + return (typeid(stream) == typeid(std::ifstream)) || (typeid(stream) == typeid(std::ofstream)) + || (typeid(stream) == typeid(std::fstream)); +} + +/****************************************************** +* Function: notFile +* return: bool +* parameters: std::istream +* +* Description: +* Returns true if the argument is not a file input stream. +* Used to decide when to prompt for stream input +******************************************************/ +bool notFile(std::ios& in) +{ + return !isFile(in); +} + + +/****************************************************** +* Function: isInteger +* return: bool +* parameters: std::string +* +* Description: +* Returns true if the argument contains only characters '0' to '9'. +* Used to verify that a string object represents an integer. +******************************************************/ +bool isInteger(string s) +{ + for (char ch : s) + { + if (!std::isdigit(ch)) + return false; + } + return true; +} + +/* +****************************************************** +* Function: display_records +* return: void +* parameters: none +* +* Description: +* Displays all the records of the chosen type. +****************************************************** +*/ +void display_records() +{ + // Display the display Record System menu + std::cout << "Choose the set of records to display.\n"; + switch (choose_person_type()) + { + case 'T': // display all teachers + std::cout << teachers; + break; + case 'S': // display all students + std::cout << students; + break; + } +} + +/****************************************************** +* Function: choose_person_type +* return: char +* parameters: none +* +* Description: +* Returns an uppercase character identifying a record type, +* either 'S' for students ot 'T' for teachers. +******************************************************/ + +char choose_person_type() +{ + char option {}; + while (true) + { + std::cout << "Choose either (S)tudent or (T)eacher: "; + std::cin >> option; + option = std::toupper(option); + if (option == 'T' || option == 'S') return option; + std::cout << "invalid choice.\n"; + } +} + +/* +****************************************************** +* Function: delete_record +* return: void +* parameters: none +* +* Description: +* Prompts for the surname of the record to be deleted +* then deletes the record from the chosen set. +****************************************************** +*/ +void delete_record() +{ + string search_name; + + while (true) + { + std::cout << "\nEnter the second name of the record you want to delete, or '.' to abort operation: "; + std::cin >> search_name; + if (search_name == ".") return; + + switch (choose_person_type()) + { + case 'T': + teachers.remove(search_name); + break; + case 'S': + students.remove(search_name); + } + } +} + +bool confirm_delete(string s) +{ + char option {}; + std::cout << "Are you sure you want to delete all " << s << " [Y/N]? "; + std::cin >> option; + if (std::toupper(option) == 'Y') + return true; + return false; +} + +/* +****************************************************** +* Function: delete_all_records +* return: void +* parameters: none +* +* Description: +* Clears a set of records of a given type, after +* confirming the user's choice. +****************************************************** +*/ +void delete_all_records() +{ + string selected; + bool deleted {false}; + switch (choose_person_type()) + { + case 'S': + selected = "students"; + if (confirm_delete(selected)) + { + students.clear(); + deleted = true; + } + break; + case 'T': + selected = "teachers"; + if (confirm_delete(selected)) + { + teachers.clear(); + deleted = true; + } + break; + } + if (deleted) + std::cout << "All " << selected << " deleted." << std::endl; + else + std::cout << "Deletion aborted." << std::endl; +} + +/* +****************************************************** +* Function: add_record +* return: void +* parameters: none +* +* Description: +* Add a single record of a chosen type, either a Student or a Teacher. +****************************************************** +*/ + + +void add_record() +{ + Student student; + Teacher teacher; + switch (choose_person_type()) + { + case 'T': + // Add a teacher record + std::cout << std::endl << "Adding Teacher record." << std::endl; + std::cin >> teacher; + teachers.add(teacher); + break; + case 'S': + // Add a student record + std::cout << std::endl << "Adding Student record." << std::endl; + std::cin >> student; + students.add(student); + break; + } +} + + +/* +****************************************************** +* Function: find_record +* return: void +* parameters: none +* +* Description: +* Prompts for a surname and searches the chosen set +* of records for the name. If the record is found +* it is displayed. +****************************************************** +*/ + +void find_record() +{ + string surname; + + // Display the Search Surname Menu + std::cout << std::endl << "Enter the Surname to Search for." << std::endl; + std::cin >> surname; + bool found {false}; + switch (choose_person_type()) + { + case 'S': + { + auto pperson = students.find(surname); + if (pperson) + { + std::cout << *pperson << std::endl; + found = true; + } + } + break; + case 'T': + { + auto pperson = teachers.find(surname); + if (pperson) + { + std::cout << *pperson << std::endl; + found = true; + } + } + break; + } + if (!found) + std::cout << surname << " not found." << std::endl; +} + +/* +****************************************************** +* Function: save_records +* return: void +* parameters: none +* +* Description: +* Save all the records to files. +****************************************************** +*/ + +void save_records() +{ + std::ofstream out {students_file}; + if (!out.is_open()) + { + std::cerr << "Cannot create output file for students." << std::endl; + return; + } + else + { + out << students; + out.close(); + std::cout << "Student records written to file." << std::endl; + } + + out.open(teachers_file); + if (!out.is_open()) + { + std::cerr << "Cannot create output file for teachers." << std::endl; + return; + } + out << teachers; + out.close(); + std::cout << "Teacher records written to file." << std::endl; +} diff --git a/9781484200087_Exercise_Solutions/Project/Project Code/Name.h b/9781484200087_Exercise_Solutions/Project/Project Code/Name.h new file mode 100644 index 0000000..e7ea9a1 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Project/Project Code/Name.h @@ -0,0 +1,58 @@ +// Encapsulates a name +/* +A name consists of a first and a second name. +There are get() and set() functions for changing a name. +A name object can be read or written to a stream using >> and << operators. +If a name is read from a stream that is not a file, input is prompted. +*/ +#ifndef NAME_H +#define NAME_H + +#include +#include +using std::string; + +bool isFile(std::ios& in); // Returns true if stream is a file +bool notFile(std::ios& in); // Returns true if not a file stream + +class Name +{ +protected: + string first_name; + string second_name; + +public: + Name() = default; + + string get_first_name() const{ return first_name; } + string get_second_name() const { return second_name; } + void set_first_name(string name) { first_name = name; } + void set_second_name(string name) { second_name = name; } + + // Compare names for equality + bool operator==(Name& name) + { + return (first_name == name.first_name) && (second_name == name.second_name); + } + + // Friend I/O functions + friend std::istream& operator>>(std::istream& in, Name& name); + friend std::ostream& operator<<(std::ostream& out, Name& name); +}; + +// Read a Name from a stream +inline std::istream& operator>>(std::istream& in, Name& name) +{ + if (notFile(in)) // If it's not a file, then prompt for input + std::cout << "Enter first and second names separated by one or more spaces: "; + in >> name.first_name >> name.second_name; + return in; +} + +// Write a name to a stream +inline std::ostream& operator<<(std::ostream& out, Name& name) +{ + out << name.first_name << " " << name.second_name << std::endl; + return out; +} +#endif \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Project/Project Code/Person.h b/9781484200087_Exercise_Solutions/Project/Project Code/Person.h new file mode 100644 index 0000000..ae4435a --- /dev/null +++ b/9781484200087_Exercise_Solutions/Project/Project Code/Person.h @@ -0,0 +1,72 @@ +// Represents a generic person +/* +A Person is defined by a Name, an Address, and a Phone number. +A specific Person is created from by reading the name, address and phone from a stream. +Input and output are supported through virtual get() and put() member functions. +This allows the operator functions for >> and << to call get() and put() polymorphically +as long as derived classes iplement get() and put() +*/ +#ifndef PERSON_H +#define PERSON_H + +#include +#include "Name.h" +#include "Address.h" +#include "Phone.h" +using std::string; + +class Person +{ +protected: + Name name; + Address address; + Phone phone; + +public: + Person() = default; + // Public Get member functions + Name get_Name() { return name; } + Address get_Address() { return address; } + Phone get_phone() const { return phone; } + + // Public Set member functions + void set_Name(Name& new_name) { name = new_name; } + void set_Address(Address& addr) {address = addr; } + void set_phone(Phone& phne) { phone = phne; } + + // Public Get member functions + Name getName() { return name; } + Address getAddress() { return address; } + Phone getPhone() { return phone; } + + // Public virtual member functions + virtual std::istream& get(std::istream& in); + virtual std::ostream& put(std::ostream& out); +}; + +// Stream output +inline std::ostream& Person::put(std::ostream& out) +{ + out << name << address << phone; + return out; +} + +// Stream output operator +inline std::ostream& operator<<(std::ostream& out, Person& person) +{ + return person.put(out); +} + +// Reading from a stream is prompted when it is not a file stream +inline std::istream& Person::get(std::istream& in) +{ + in >> name >> address >> phone; + return in; +} + +// Stream input operator +inline std::istream& operator>>(std::istream& in, Person& person) +{ + return person.get(in); +} +#endif \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Project/Project Code/Phone.h b/9781484200087_Exercise_Solutions/Project/Project Code/Phone.h new file mode 100644 index 0000000..58f3d8b --- /dev/null +++ b/9781484200087_Exercise_Solutions/Project/Project Code/Phone.h @@ -0,0 +1,115 @@ +// Encapsulates a phone number +/* +A US phone number has three parts: a 3 digit area code, a 3 digit exchange code and a 4 digit number. +The number of digits for the three parts are validated. +The area code and exchange codes are checked for a valid initial digit. +The exchange code is also checked to verify that the last two digits are not 11. +There are further restriction on digits that could be checked but are not included here. +Input and output is supported through the >> and << operators. +Input from a stream that is not a file is prompted and validated. +*/ +#ifndef PHONE_H +#define PHONE_H +#include // For isdigit() +#include // For standard streams +#include // For file streams +#include // For string +using std::string; + +class Phone +{ +protected: + // The members are strings to maintain the number of digits with a leading zero + // Remember - an integer with a leading zero is octal! + string area_code; // 3 digits between 200 and 999 + string exchange_code; // 3 digits between 200 and 999 but not '#11' + string number; // 4 digits 0 to 9999 + +public: + Phone() = default; + + // Friend I/O functions + friend std::istream& operator>>(std::istream& in, Phone& phone); + friend std::ostream& operator<<(std::ostream& out, Phone& phone); +}; + +// Input a phome number from the keyboard +inline std::istream& operator>>(std::istream& in, Phone& phone) +{ + if (isFile(in)) + { + in >> phone.area_code >> phone.exchange_code >> phone.number; + return in; + } + + // Input stream is not a file so we need to prompt and check + // Get the area code + while (true) + { + std::cout << "Enter 3-digit area code: "; + in >> phone.area_code; + if (phone.area_code[0] == '0' || phone.area_code[0] == '1' || phone.area_code.length() != 3 || !isInteger(phone.area_code)) + { + std::cout << "A valid area code has 3 digits with the first digit from 2 to 9, try again.\n"; + continue; + } + else + break; + } + + // Get the exchange code + while (true) + { + std::cout << "Enter 3-digit exchange code: "; + in >> phone.exchange_code; + if (phone.exchange_code[0] == '0' || phone.exchange_code[0] == '1' || !isInteger(phone.exchange_code)) + { + std::cout << "A valid exchange code must be 3 digits with the first digit from 2 to 9, try again.\n"; + continue; + } + else if (phone.exchange_code[1] == '1' && phone.exchange_code[2] == '1') + { + std::cout << "Invalid exchange code - the last two digits must not be 11, try again.\n"; + continue; + } + else + break; + } + + // Get number + while (true) + { + std::cout << "Enter the number: "; + in >> phone.number; + if (phone.number.length() != 4 || !isInteger(phone.number)) + { + std::cout << "The number must be four digits. Try again."; + continue; + } + bool numeric {true}; + for (auto ch : phone.number) + { + if (!std::isdigit(ch)) + { + numeric = false; + break; + } + } + if (!numeric) + { + std::cout << "The number must be numeric. Try again."; + continue; + } + break; + } + return in; +} + + +// Stream output for a phone number +inline std::ostream& operator<<(std::ostream& out, Phone& phone) +{ + out << phone.area_code << " " << phone.exchange_code << " " << phone.number << std::endl; + return out; +} +#endif \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Project/Project Code/Student.h b/9781484200087_Exercise_Solutions/Project/Project Code/Student.h new file mode 100644 index 0000000..2c8e793 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Project/Project Code/Student.h @@ -0,0 +1,75 @@ +/* +**************************************************************** +* +* The "Student" Class inherited from the +* "Person" base Class. +* +**************************************************************** +*/ +#ifndef STUDENT_H +#define STUDENT_H + +#include +#include +#include "Person.h" +using std::string; + +class Student : public Person +{ +protected: + string student_ID; + int grade {}; + +public: + Student() = default; + std::istream& get(std::istream& in) override; + std::ostream& put(std::ostream& out) override; +}; + +// Read a student record from a stream +inline std::istream& Student::get(std::istream& in) +{ + Person::get(in); // Deal with the base part of the object + if (isFile(in)) // It we are reading a file... + { // ...no prompting or checking is necessary. + in >> student_ID >> grade; + } + else + { // Not a file, so prompt for input + while (true) + { + std::cout << "Enter the student ID (IDnnnn): "; + in >> student_ID; + if (student_ID.length() == 6 && // Must be 6 character and... + student_ID.substr(0,2) == "ID" && // ...start with "ID" followed by... + isInteger(student_ID.substr(2,4))) // ...four decimal digits + break; + std::cout << "Invalid grade format. Should be IDnnnn. Try again.\n"; + } + while (true) + { + std::cout << "Enter the student's grade: "; + in >> grade; + if (grade >= 0 && grade <= 100) break; + std::cout << "Grade is a percentile and must be from 0 to 100. Try again.\n"; + } + } + return in; +} + +// Write a student record to a stream +inline std::ostream& Student::put(std::ostream& out) +{ + Person::put(out); // Write the base part of the object + if (isFile(out)) // If we are writing a file... + { + out << student_ID << " \n" << grade << std::endl; // ...just write the data + } + else + out << "Student ID: "<< student_ID << "\n" + << "Grade: " << grade << std::endl; + + return out; +} + +#endif diff --git a/9781484200087_Exercise_Solutions/Project/Project Code/Teacher.h b/9781484200087_Exercise_Solutions/Project/Project Code/Teacher.h new file mode 100644 index 0000000..00cc022 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Project/Project Code/Teacher.h @@ -0,0 +1,65 @@ +// Class representing a teacher +/* +**************************************************************** +* +* The Teacher Class inherits from the +* "Person" base Class. +* +**************************************************************** +*/ +#ifndef TEACHER_H +#define TEACHER_H + +bool isFile(std::ios& in); // Returns true if stream is a file +bool notFile(std::ios& in); // Returns true if not a file stream + +#include +#include "Person.h" +using std::string; + +class Teacher : public Person +{ +protected: + size_t years_experience; + long salary; + +public: + Teacher() = default; + std::istream& get(std::istream& in) override; + std::ostream& put(std::ostream& out) override; +}; + +// Read a teacher record from a stream +inline std::istream& Teacher::get(std::istream& in) +{ + Person::get(in); + if (isFile(in)) // If it's a file... + { + in >> years_experience >> salary; // ...just read the data + } + else // ...otherwise - prompt for input + { + std::cout << "Enter the number of years experience: "; + in >> years_experience; + std::cout << "Enter the salary(integral number of $: "; + in >> salary; + } + return in; +} + +// Write a teacher record to a stream +inline std::ostream& Teacher::put(std::ostream& out) +{ + Person::put(out); // Write the base part + if (isFile(out)) // If we are writing a file... + { + out << years_experience << "\n" << salary << std::endl; // ...just write tha data + } + else + { + out << "Experience: " << years_experience << " years\n" + << "Salary: $" << salary << std::endl; + } + return out; +} +#endif \ No newline at end of file diff --git a/9781484200087_Exercise_Solutions/Project/Project Description.txt b/9781484200087_Exercise_Solutions/Project/Project Description.txt new file mode 100644 index 0000000..013a458 --- /dev/null +++ b/9781484200087_Exercise_Solutions/Project/Project Description.txt @@ -0,0 +1,89 @@ +Example Project: +You’ve read the book. You’ve digested the text. Now it’s time to apply your newfound knowledge to a small, but +perfectly formed project. I’ll describe the problem here and give some hints on how to solve it. +Outline +The aim of the project is to create a program that keeps track of information about teachers and students in an +educational establishment. This information will be held as a series of Teacher and Student records, both of which will +contain the following attributes: + +First Name: Alphabetic +Surname: Alphabetic +Address: Mixed - One or more lines of street address. +City: Alphabetic +State: Alphabetic +Zip Code: Numeric - Must be 5 digits. +Phone Number: Numeric - Must be of the form ###--###-####. The area code must not have a leading digit of 0 or 1. +The last two exchange code digits must not be 11. + +Student records will have these additional attributes: + +Student ID: Alphanumeric - Form is "IDnnn" where n is a decimal digit +Grade (percentile): Numeric - Integer between 0 and 100. + +Teacher records will have the following additional attributes: + +Teaching experience (in years): Numeric - obviously must be positive integer +Salary: Numeric - obviously must be positive integer + +The program should support the following operations for students and teachers: + +* Add a record +* Search for a record by surname and display it. +* Display all the student records or all the teacher records. +* Find and delete a record. +* Delete all the records for students and/or teachers + +The records for students and teachers should be backed up in a file or files so that when the program starts the +current set of teacher and student records are available. When a record is added, all the attributes of the student or +teacher should be properly entered by the user. The street address can consist of one or more lines. + +When a user deletes a record, they should be prompted to enter the surname of the teacher or student record +they wish to delete. Once deleted, a record can’t be searched for or displayed. There should be a way to deal with +duplicate surnames resulting from searches + +When a user searches for a record, they should be prompted to enter the surname of the record they wish to +find. The program should then display all the attributes of the record containing the desired surname (i.e., if the record +refers to a Student, then the Grade and Student ID fields should be displayed). + +Developer Notes: +Here are a few suggestions on how you might approach implementing the program: +* Define the types of objects required by the implementation first. +* Map out the basic logic and the operations needed for each of the object types. +* Have the objects take care of themselves in terms of data validation and input and output as far as possible. +* Use a container class to organize the objects. +* Use the main() function as a switch that directs program execution based on user input resulting from a menu of options. +* Make sure that you test all the options, including incorrect data entry. + +My Solution: +There is no unique solution to this exercise. Because the specification is open to interpretation there is huge flexibility +in the possible approaches to solving the problem. My solution is not necessarily the best by any means. I chose to +include as many of the programming techniques I discuss in the book that would fit reasonably with the problem but +they are not all essential in an implementation. + +The Person class contains the basic structure of both the derived Student and Teacher classes. The Person class +contains most of the code associated with the classes representing individuals and provides for polymorphic behavior. +It is structured to take full advantage of member variable data hiding and operator overloading. The data members of +the Person class are also objects of types Name, Address, and Phone. This allows the characteristics of these types to +be changed without necessarily changing the rest of the program. These types also implement data validation where +appropriate and take care of input and output. The Address and Phone classes assume US specifications but these +could easily be changed to support other national contexts. + +The containers for students and teachers are defined by a Group class template. All instances of Group store +smart pointers to objects in the free store of the same type, std::shared_ptr. Using smart pointers means that +deletions of objects in the free store is taken care of. Because copies are of objects of type T are created, class T must +support copying. + +Saving and restoring data is automatic in my solution. Data is retrieved from files when the program starts and the +current state is saved when the program ends. I chose not to update the files when a student or teacher was added or +deleted but you could. This would provide some protection for the data against crashes, which might occur due to +external events that are nothing to do with the program. + +There are a lot of ways in which this program can be improved or extended, so you could use it as a basis to try out +more programming techniques and gain experience with managing a lot of code by extending the functionality. The +program could provide for outputting data sorted by name; students could be output ordered by Grade and teachers +could be optionally in order of experience for example. At present there's no provision for updating records once they +have been created. All such extensions require interesting additions to the capabilities of the classes. + +Above all, remember that if you use C++ in a clean and simple way, code maintenance will be very much easier. +Always assume that another developer will be looking over your code and will need to understand how it works— +you’ll be thankful you did so in the long run!