NTOU CSE C++ Programming
教學文件和作業說明文件: https://hackmd.io/@kogiokka/ntou-cse-cpp-nav
本次實習主題是程式設計中的配接器模式(Adapter Pattern)。還有練習 C++ 的繼承(inheritance)、虛擬函式(virtual functions)和抽象類別(abstract class)。
<學號>-<姓名>.zip
,例如:11057666-陳小明.zip
。承第十二次實習作業。依配接器模式(Adapter Pattern)設計一或多個 Adaptee 和 Adapter。負責測試案例的是範例程式中的 Client
類別,Client
會透過 LookUpTable
抽象類別呼叫 Adapters 所提供的函式。
Client
的測試案例。附帶的測試資料 TestData/BookList.csv
是逗號分隔值檔(comma-separated values file)。除了用 Spreadsheet 軟體(例:MS Excel)瀏覽和編輯,也可以用純文字檔的方式開啟和編輯(例:VS Code、Notepad++)。
不是使用 Visual Studio 嗎?請見 CMake專案建置。
在 Visual Studio 選擇開啟本機資料夾或檔案 → 開啟 → 資料夾,並選擇AdapterPattern_Enhanced/
的資料夾。Visual Studio 會自動開始設定 CMake 專案。等待輸出欄位的訊息跑完之後,在上方工具列的選取啟動項目選 adapter-enhanced.exe (安裝)
就可以自動編譯執行了。
如果不是使用 Visual Studio,可能需要自行定義 CMAKE_INSTALL_PREFIX
變數,並做其他設定。詳情請見CMake專案建置的「CMake安裝指令的相關設定」一節。
AdapterPattern_Enhanced
├── CMakeLists.txt
├── Source
│ ├── Adapter
│ │ ├── AdapterClass.cpp
│ │ ├── AdapterClass.hpp
│ │ ├── AdapterObject.cpp
│ │ └── AdapterObject.hpp
│ ├── Book.cpp
│ ├── Book.hpp
│ ├── Client
│ │ ├── Client.cpp
│ │ └── Client.hpp
│ ├── ClientInterface
│ │ └── LookUpTable.hpp
│ ├── CMakeLists.txt
│ ├── main.cpp
│ ├── Service
│ │ ├── Adaptee.cpp
│ │ └── Adaptee.hpp
│ └── Utilities
│ ├── Console.cpp
│ ├── Console.hpp
│ ├── Helpers.cpp
│ ├── Helpers.hpp
│ ├── Timer.cpp
│ └── Timer.hpp
└── TestData
└── BookList.csv
TestData/BookList.csv
"C++17 STL Cookbook","Jacek Galowicz",49.99
"Boost C++ Application Development Cookbook Second Edition","Antony Polukhin",49.99
"Mastering C++ Programming","Jeganathan Swaminathan",49.99
"C++ High Performance","Viktor Sehr, Bjorn Andrist",44.99
"C++ Crash Course: A Fast-Paced Introduction Illustrated Edition","Josh Lospinoso",50.40
"C++ Primer","Stanley Lippman,Josée Lajoie,Barbara Moo",40.94
"Effective Modern C++","Scott Meyers",49.01
"C++ Programming Language (hardcover), The 4th Edition","Bjarne Stroustrup",66.99
"C++ Standard Library Quick Reference 1st ed. Edition","Peter Van Weert,Marc Gregoire",34.71
"The Modern C++ Challenge","Marius Bancila",34.99
"Hands-On Design Patterns with C++","Fedor G. Pikus",49.99
"Hands-On Embedded Programming with C++17","Maya Posch",44.99
"Hands-On System Programming with C++","Dr. Rian Quinn",44.99
"Modern C","Jens Gustedt",59.99
"C++ Concurrency in Action, Second Edition","Anthony Williams",69.99
"Modern Fortran","Milan Curcic",59.99
"Math for Programmers","Paul Orland",59.99
"The Java Module System","Nicolai Parlog,Kevlin Henney",49.99
"Modern Java in Action","Raoul-Gabriel Urma,Mario Fusco,Alan Mycroft",54.99
"Enterprise Java Microservices","Ken Finnigan",49.99
"Functional Programming in C++","Ivan Čukić",49.99
"Learning Perl Sixth Edition","Randal L. Schwartz,brian d foy,Tom Phoenix",24.06
"Programming Perl","Tom Christiansen,brian d foy,Larry Wall,Jon Orwant",27.00
"The Joy of Kotlin","Pierre-Yves Saumont",49.99
"Functional Programming in Java","Pierre-Yves Saumont",49.99
CMakeLists.txt
cmake_minimum_required(VERSION 3.12)
project("Adapter Pattern")
# 執行 "Source/" 資料夾中的 CMakeLists.txt
add_subdirectory("Source/")
Source/Book.cpp
#include "Book.hpp"
using std::ostream;
using std::string;
using std::vector;
Book::Book()
: m_name("")
, m_authors({})
, m_price(0)
{
}
Book::Book(const string& name, const vector<string>& authors, float price)
: m_name(name)
, m_authors(authors)
, m_price(price)
{
}
void Book::assign(const string& name, const vector<string>& authors, float price)
{
m_name = name;
m_authors = authors;
m_price = price;
}
std::string Book::name() const
{
return m_name;
}
std::vector<std::string> Book::authors() const
{
return m_authors;
}
float Book::price() const
{
return m_price;
}
Source/Book.hpp
#ifndef BOOK_H_
#define BOOK_H_
#include <iostream>
#include <string>
#include <vector>
class Book
{
friend std::ostream& operator<<(std::ostream&, const Book&);
private:
std::string m_name;
std::vector<std::string> m_authors;
float m_price;
public:
Book();
Book(const std::string& name, const std::vector<std::string>& authors, float price);
void assign(const std::string& name, const std::vector<std::string>& authors, float price);
std::string name() const;
std::vector<std::string> authors() const;
float price() const;
};
#endif // BOOK_H_
Source/CMakeLists.txt
add_executable(adapter-enhanced)
# 新增 include 路徑
# #include 指令中的相對路徑會從專案根目錄之下的 "Source" 資料夾開始計算
target_include_directories(adapter-enhanced PRIVATE "${CMAKE_SOURCE_DIR}/Source")
target_sources(adapter-enhanced
PRIVATE
"Adapter/AdapterClass.cpp"
"Adapter/AdapterObject.cpp"
"Client/Client.cpp"
"Book.cpp"
"Service/Adaptee.cpp"
"Utilities/Console.cpp"
"Utilities/Helpers.cpp"
"Utilities/Timer.cpp"
"main.cpp"
)
install(TARGETS adapter-enhanced DESTINATION .)
install(DIRECTORY "${CMAKE_SOURCE_DIR}/TestData" DESTINATION .)
Source/main.cpp
#include "Adapter/AdapterClass.hpp"
#include "Adapter/AdapterObject.hpp"
#include "Book.hpp"
#include "Client/Client.hpp"
#include "ClientInterface/LookUpTable.hpp"
#include "Utilities/Console.hpp"
#include "Utilities/Helpers.hpp"
int main()
{
BANNER();
CUT();
Client client;
client.importBooksFromFile("TestData/BookList.csv");
CUT();
/**
// Adaptee 1
{
HEAD1("AdapterClass1");
AdapterClass adapter1;
client.test(&adapter1);
END();
CUT();
HEAD1("AdapterObject1");
AdapterObject adapter2;
client.test(&adapter2);
END();
}
*/
/**
// Adaptee 2
{
HEAD1("AdapterClass2");
AdapterClass2 adapter1;
client.test(&adapter1);
END();
CUT();
HEAD1("AdapterObject2");
AdapterObject2 adapter2;
client.test(&adapter2);
END();
}
*/
PAUSE();
}
Source/Adapter/AdapterClass.cpp
#include <limits>
#include "Adapter/AdapterClass.hpp"
#include "Utilities/Helpers.hpp"
// TODO
Source/Adapter/AdapterClass.hpp
#ifndef ADAPTERCLASS_H_
#define ADAPTERCLASS_H_
#include <string>
#include <vector>
#include "Book.hpp"
#include "ClientInterface/LookUpTable.hpp"
#include "Service/Adaptee.hpp"
class AdapterClass : public LookUpTable, public Adaptee
{
public:
int add(const Book& book) override;
int remove(const std::string& bookName, const std::vector<std::string>& authors, float price) override;
Book* find(const std::string& bookName) override;
Book* find(const std::string& bookName, const std::vector<std::string>& authors) override;
Book mostExpensive() override;
Book cheapest() override;
float average() override;
void clean() override;
};
#endif // ADAPTERCLASS_H_
Source/Adapter/AdapterObject.cpp
#include <limits>
#include "Adapter/AdapterObject.hpp"
#include "Utilities/Helpers.hpp"
// TODO
Source/Adapter/AdapterObject.hpp
#ifndef ADAPTEROBJECT_H_
#define ADAPTEROBJECT_H_
#include <string>
#include "Book.hpp"
#include "ClientInterface/LookUpTable.hpp"
#include "Service/Adaptee.hpp"
class AdapterObject : public LookUpTable
{
private:
Adaptee ad;
public:
int add(const Book& val) override;
int remove(const std::string& bookName, const std::vector<std::string>& authors, float price) override;
Book* find(const std::string& bookName) override;
Book* find(const std::string& bookName, const std::vector<std::string>& authors) override;
Book mostExpensive() override;
Book cheapest() override;
float average() override;
void clean() override;
};
#endif // ADAPTEROBJECT_H_
Source/Client/Client.cpp
#include <cstdlib>
#include <ctime>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
#include "Client.hpp"
#include "Utilities/Console.hpp"
#include "Utilities/Helpers.hpp"
#include "Utilities/Timer.hpp"
/* <string> */
using std::getline;
using std::stof; // string to float
using std::string;
using std::to_string;
/* <sstream> */
using std::istringstream;
/* <fstream> */
using std::ifstream;
/* <iostream> */
using std::cerr;
using std::cout;
using std::endl;
/* <iomanip> */
using std::quoted;
/* <vector> */
using std::vector;
/* <cstdlib> */
using std::exit;
using std::srand;
/* <ctime> */
using std::time;
/* Test Cases */
void Client::test(LookUpTable* table)
{
m_books.push_back(csv2Book(R"csv("Beginning C++20: From Novice to Professional","Ivor Horton",38.60)csv"));
HEAD2("Test LookUpTable::add");
{
string sep = "";
cout << "add: ";
for (const auto& book : m_books) {
cout << sep << table->add(book); // Ans: 1
sep = ", ";
}
cout << endl;
}
END();
HEAD2("Test Price Information");
{
cout << "Most expensive book: " << table->mostExpensive() << endl;
cout << "Cheapest book: " << table->cheapest() << endl;
cout << "Average price: " << table->average() << endl;
/**
Ans:
Most expensive book: {"C++ Concurrency in Action, Second Edition", ["Anthony Williams"], 69.99}
Cheapest book: {"Learning Perl Sixth Edition", ["Randal L. Schwartz", "brian d foy", "Tom Phoenix"], 24.06}
Average price: 48.3281
*/
}
END();
HEAD2("Test LookUpTable::add, again");
{
string sep = "";
cout << "add: ";
for (const auto& book : m_books) {
cout << sep << table->add(book); // Ans: 0
sep = ", ";
}
cout << endl;
}
END();
HEAD2("Test Price Information, again");
{
cout << "Most expensive book: " << table->mostExpensive() << endl;
cout << "Cheapest book: " << table->cheapest() << endl;
cout << "Average price: " << table->average() << endl;
/**
Ans:
Most expensive book: {"C++ Concurrency in Action, Second Edition", ["Anthony Williams"], 69.99}
Cheapest book: {"Learning Perl Sixth Edition", ["Randal L. Schwartz", "brian d foy", "Tom Phoenix"], 24.06}
Average price: 48.3281
*/
}
END();
HEAD2("Test LookUpTable::remove");
{
Book book("C++ High Performance", { "Viktor Sehr", "Bjorn Andrist" }, 44.99f);
cout << "remove: " << table->remove(book.name(), book.authors(), book.price()) << "\n"; // Ans: remove: 1
}
{
Book book = csv2Book(R"csv("Modern Fortran","Mr. Curcic",0.0)csv");
cout << "remove: " << table->remove(book.name(), book.authors(), book.price()) << "\n"; // Ans: remove: 0
}
{
Book book = csv2Book(R"csv("Modern Fortran","Milan Curcic",59.99)csv");
cout << "remove: " << table->remove(book.name(), book.authors(), book.price()) << "\n"; // Ans: remove: 1
}
{
Book book = csv2Book(
R"csv("C++ Concurrency in Action, Second Edition","Anthony Williams",69.99)csv"); // Ans: remove: 1
cout << "remove: " << table->remove(book.name(), book.authors(), book.price()) << "\n";
}
string sep = "";
cout << "remove: ";
for (const auto& book : m_books) {
cout << sep << table->remove(book.name(), book.authors(), book.price());
sep = ", ";
}
cout << endl;
END();
for (const auto& book : m_books) {
table->add(book);
}
HEAD2("Test LookUpTable::find");
{
int id = 18;
Book* ptr = nullptr;
string name = m_books[id].name();
vector<string> authors = m_books[id].authors();
ptr = table->find(name, authors);
if (ptr) {
cout << "Success. Found " << *ptr << endl; // Ans
} else {
cout << "Fail. Could not find " << quoted(name) << ", " << authors << endl;
}
authors = { m_books[id].authors().front() };
ptr = table->find(name, authors);
if (ptr) {
cout << "Success. Found " << *ptr << endl;
} else {
cout << "Fail. Could not find " << quoted(name) << ", " << authors << endl; // Ans
}
id = 10;
name = m_books[id].name();
authors = m_books[id].authors();
ptr = table->find(name, authors);
if (ptr) {
cout << "Success. Found " << *ptr << endl; // Ans
} else {
cout << "Fail. Could not find " << quoted(name) << ", " << authors << endl;
}
authors = { m_books[id].authors().front() };
ptr = table->find(name, authors);
if (ptr) {
cout << "Success. Found " << *ptr << endl; // Ans
} else {
cout << "Fail. Could not find " << quoted(name) << ", " << authors << endl;
}
}
END();
HEAD2("Test LookUpTable::clean");
{
Book* ptr = nullptr;
string name = "Modern Java in Action";
vector<string> authors = { "Raoul-Gabriel Urma", "Mario Fusco", "Alan Mycroft" };
ptr = table->find(name, authors);
if (ptr) {
cout << "Success. Found " << *ptr << endl; // Ans
} else {
cout << "Fail. Could not find " << quoted(name) << ", " << authors << endl;
}
table->clean();
cout << "Cleaned the LookUpTable." << endl;
ptr = table->find(name, authors);
if (ptr) {
cout << "Success. Found " << *ptr << endl;
} else {
cout << "Fail. Could not find " << quoted(name) << ", " << authors << endl; // Ans
}
}
END();
stressTesting(table);
}
void Client::stressTesting(LookUpTable* table)
{
HEAD2("Stress Testing");
{
Timer timer;
srand(time(0));
for (int i = 0; i < 1000; i++) {
string str1 = "Stress Testing" + to_string(i);
Book book(str1, { str1 }, static_cast<float>(rand() % 200) * 0.65f);
table->add(book);
}
for (int i = 0; i < 1000; i++) {
string str1 = "Stress Testing" + to_string(i);
table->find(str1);
}
for (int i = 0; i < 1000; i++) {
string str1 = "Stress Testing" + to_string(i);
table->find(str1, { str1 });
}
for (int i = 0; i < 1000; i++) {
string str1 = "Stress Testing" + to_string(i);
table->remove(str1, { str1 }, static_cast<float>(rand() % 200) * 0.65f);
}
}
END();
}
void Client::importBooksFromFile(const string& filename)
{
ifstream file;
file.open(filename);
if (!file.good()) {
cerr << "Failed to open the file: " << quoted(filename) << endl;
exit(EXIT_FAILURE);
return;
}
Book book;
string line;
vector<Book> books;
while (getline(file, line)) {
books.push_back(csv2Book(line));
}
file.close();
m_books.insert(m_books.end(), books.begin(), books.end());
cout << "Successfully import " << books.size() << " books:" << endl;
for (unsigned int i = 1; i <= books.size(); i++) {
cout << i << ". " << books[i - 1] << endl;
}
}
void Client::importBookCSV(const string& csv)
{
m_books.push_back(csv2Book(csv));
}
Book Client::csv2Book(const string& text) const
{
Book book;
string name, authors, price;
istringstream lineStream(text);
lineStream >> quoted(name); // Get the quoted content
lineStream.get(); // remove comma
lineStream >> quoted(authors); // Get the quoted content
lineStream.get(); // remove comma
lineStream >> price;
lineStream.get(); // remove comma
// split function is from Utilities/Helper
book.assign(name, split(authors, ','), stof(price));
return book;
}
void Client::clearBooks()
{
m_books.clear();
}
Source/Client/Client.hpp
#ifndef CLIENT_H_
#define CLIENT_H_
#include <string>
#include <vector>
#include "Book.hpp"
#include "ClientInterface/LookUpTable.hpp"
class Client
{
std::vector<Book> m_books;
public:
void test(LookUpTable* table);
void stressTesting(LookUpTable* table);
void importBooksFromFile(const std::string& filename);
void importBookCSV(const std::string& csv);
void clearBooks();
private:
Book csv2Book(const std::string& text) const;
};
#endif // CLIENT_H_
Source/ClientInterface/LookUpTable.hpp
#ifndef LOOKUPTABLE_H_
#define LOOKUPTABLE_H_
#include <string>
#include <vector>
#include "Book.hpp"
class LookUpTable
{
public:
/**
Add a book into the table
@param book the book to be added
@return 1 for success and 0 for failure
*/
virtual int add(const Book& book) = 0;
/**
Remove a book from the table
@param name name of the book
@param authors authors of the book
@param price price of the book
@return 1 for success and 0 for failure
*/
virtual int remove(const std::string& name, const std::vector<std::string>& authors, float price) = 0;
/**
Find a book from the table
@param name name of the book
@return pointer to the book if the search succeed, otherwise nullptr
*/
virtual Book* find(const std::string& name) = 0;
/**
Find a book from the table
@param name name of the book
@param authors authors of the book
@return pointer to the book if the search succeed, otherwise nullptr
*/
virtual Book* find(const std::string& name, const std::vector<std::string>& authors) = 0;
/**
Get the most expensive book from the table
@return the most expensive book
*/
virtual Book mostExpensive() = 0;
/**
Get the cheapest book from the table
@return the cheapest book
*/
virtual Book cheapest() = 0;
/**
Get the average price of the books in the table
@return the average price
*/
virtual float average() = 0;
/**
Remove all the books from the table
*/
virtual void clean() = 0;
};
#endif // LOOKUPTABLE_H_
Source/Service/Adaptee.cpp
#include "Service/Adaptee.hpp"
#include "Utilities/Helpers.hpp"
/**
~~~~
TODO
~~~~
需求
----
每一個 Adaptee 類別都要搭配兩個 Adapter 類別。其中一個以多重繼承(inheritance
)的方法實作,而另一個以複合(composition)的方法實作。
計分
----
* 任一種 Adaptee:80 分
* 有 BinaryTree 類型的 Adaptee:20 分
* 每新增一種不同類型的 Adaptee:20 分
* 最高分 120 分
*/
Source/Service/Adaptee.hpp
#ifndef ADAPTEE_H_
#define ADAPTEE_H_
#include <map>
#include <string>
#include "Book.hpp"
class Adaptee
{
std::map<std::string, Book> mapBook;
public:
// TODO
};
// class BinaryTree
// {
// };
#endif // ADAPTEE_H_
Source/Utilities/Console.cpp
#include <iostream>
#include "Utilities/Console.hpp"
/* <iostream> */
using std::cout;
using std::endl;
/* <string> */
using std::string;
static void _HEAD_INTERNAL(const string& text, char ch);
void BANNER()
{
cout << R"AdapterPattern2(
** ** **
**** /** ****** /**
**//** /** ****** /**///** ****** ***** ******
** //** ****** //////** /** /**///**/ **///**//**//*
********** **///** ******* /****** /** /******* /** /
/**//////**/** /** **////** /**/// /** /**//// /**
/** /**//******//********/** //** //******/***
// // ////// //////// // // ////// ///
******* ** **
/**////** /** /**
/** /** ****** ****** ****** ***** ****** *******
/******* //////** ///**/ ///**/ **///**//**//*//**///**
/**//// ******* /** /** /******* /** / /** /**
/** **////** /** /** /**//// /** /** /**
/** //******** //** //** //******/*** *** /**
// //////// // // ////// /// /// //
******** ** **
/**///// /** /**
/** ******* /** ****** ******* ***** ***** /**
/******* //**///**/****** //////** //**///** **///** **///** ******
/**//// /** /**/**///** ******* /** /**/** // /******* **///**
/** /** /**/** /** **////** /** /**/** **/**//// /** /**
/******** *** /**/** /**//******** *** /**//***** //******//******
//////// /// // // // //////// /// // ///// ////// //////
)AdapterPattern2";
}
void HEAD1(const string& text)
{
string tildes(text.length(), '~');
cout << tildes << "\n";
cout << text << "\n";
cout << tildes << "\n\n";
}
void HEAD2(const string& text)
{
_HEAD_INTERNAL(text, '^');
}
void HEAD3(const string& text)
{
_HEAD_INTERNAL(text, '*');
}
void END()
{
cout << endl;
}
void CUT()
{
string line(80, '=');
cout << line << "\n" << endl;
}
// Portable system("pause")
void PAUSE()
{
cout << "Press enter to continue..." << endl;
std::cin.get();
}
static inline void _HEAD_INTERNAL(const string& text, char ch)
{
string line(text.length(), ch);
cout << text << "\n";
cout << line << "\n\n";
}
Source/Utilities/Console.hpp
#ifndef CONSOLE_H_
#define CONSOLE_H_
#include <string>
void BANNER();
void HEAD1(const std::string& text);
void HEAD2(const std::string& text);
void HEAD3(const std::string& text);
void END();
void CUT();
void PAUSE();
#endif // CONSOLE_H_
Source/Utilities/Helpers.cpp
#include <iomanip>
#include <sstream>
#include <string>
#include "Helpers.hpp"
/* <iostream> */
using std::cout;
using std::endl;
using std::ostream;
/* <string> */
using std::getline;
using std::string;
/* <sstream> */
using std::istringstream;
using std::ostringstream;
/* <map> */
using std::map;
/* <vector> */
using std::vector;
/* <iomanip> */
using std::quoted;
vector<string> split(string text, char delim)
{
vector<string> result;
string token;
istringstream textStream(text);
while (getline(textStream, token, delim)) {
result.push_back(token);
}
return result;
}
ostream& operator<<(ostream& out, const vector<string>& vec)
{
ostringstream vectorStream;
string separator = "";
vectorStream << "[";
for (auto it = vec.begin(); it != vec.end(); ++it) {
vectorStream << separator << quoted(*it);
separator = ", ";
}
vectorStream << "]";
return (out << vectorStream.str());
}
ostream& operator<<(ostream& out, const Book& book)
{
ostringstream bookStream;
bookStream << "{" << quoted(book.m_name) << ", " << book.m_authors << ", " << book.m_price << "}";
return (out << bookStream.str());
}
ostream& operator<<(ostream& out, const map<string, Book>& books)
{
ostringstream booksJSON;
string separator = "";
const string indent = " ";
booksJSON << "{\n";
for (auto it = books.begin(); it != books.end(); ++it) {
booksJSON << separator << indent << quoted(it->first) << ": {\n"
<< indent << indent << quoted("name") << ": " << quoted(it->second.name()) << ",\n"
<< indent << indent << quoted("authors") << ": " << it->second.authors() << ",\n"
<< indent << indent << quoted("price") << ": " << it->second.price() << "\n"
<< indent << "}";
separator = ",\n";
}
booksJSON << "\n}" << endl;
return (out << booksJSON.str());
}
bool operator==(const std::vector<std::string>& vec1, const std::vector<std::string>& vec2)
{
if (vec1.size() != vec2.size()) {
return false;
}
for (unsigned int i = 0; i < vec1.size(); i++) {
if (vec1[i] != vec2[i]) {
return false;
}
}
return true;
}
Source/Utilities/Helpers.hpp
#ifndef HELPERS_H_
#define HELPERS_H_
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include "Book.hpp"
std::vector<std::string> split(std::string text, char delim);
std::ostream& operator<<(std::ostream& out, const std::vector<std::string>& vec);
std::ostream& operator<<(std::ostream& out, const Book& book);
std::ostream& operator<<(std::ostream& out, const std::map<std::string, Book>& books);
bool operator==(const std::vector<std::string>& vec1, const std::vector<std::string>& vec2);
#endif // HELPERS_H_
Source/Utilities/Timer.cpp
#include "Timer.hpp"
#include <iostream>
#include <ratio>
/* <chrono> */
namespace chr = std::chrono;
/* <ratio> */
using std::ratio;
/* <iostream> */
using std::cout;
using std::endl;
Timer::Timer()
{
m_start = chr::steady_clock::now();
}
Timer::~Timer()
{
const auto end = chr::steady_clock::now();
chr::duration<double, ratio<1, 1>> secs = end - m_start;
chr::duration<double, ratio<1, 1000000>> microSecs = end - m_start;
cout << "The operation(s) took " << secs.count() << " seconds (" << microSecs.count() << " microseconds)." << endl;
}
Source/Utilities/Timer.hpp
#ifndef TIMER_H_
#define TIMER_H_
#include <chrono>
/**
* @class Timer
*
* The timer will start right after the instantiation, and print the duration to
* standard output when the object is destroyed.
*/
class Timer
{
std::chrono::time_point<std::chrono::steady_clock> m_start;
public:
Timer();
~Timer();
};
#endif // TIMER_H_