6. polymorphism, I/O, String streams, Cmake find_package
30 May 2020 | Modern C++
Polymorphism(something take many shape)
- Allows morphing(变形) derived classes into their base class type:
- const Base& base = Derived(…)
- there are relationship between A and B
When is it useful?
- Allows encapsulating the implementation inside a class only asking it to conform to a common interface
- 즉 이미지 프로세싱에 있어 두가징 방법으로 같은 결과 구함(이미지 한장가지고 여러 가지 일을 함 : Canny detection , bitwise )
- Often used for:
- Working with all children of some Base class in unified(统一) manner
- Enforcing an interface in multiple classes to force them to implement some functionality
- In strategy pattern, where some complex functionality is outsourced into separate classes and is passed to the object in a modular fashion
- image class we want to save two difference processed picture.
Creating a class hierarchy
- Sometimes classes must form a hierarchy
- Distinguish between is a and has a to test if the classes should be in one hierarchy:
- Square is a Shape: can inherit from Shape
- Student is a Human: can inherit from Human
- Car has a Wheel: should not inherit each other
- Prefer shallow hierarchies
- GOOGLE-STYLE Prefer composition, i.e. including an object of another class as a member of your class
Example 1
#include <iostream>
using std::cout; using std::endl;
class Rect{
public:
Rect(int w, int h) : w_{w}, h_{h} {}
virtual void Print() const {
cout << "Rect: " << w_ << "x" <<h_ <<endl;
}
private:
int w_ = 0;
int h_ = 0;
};
struct Square : public Rect{
explicit Square(int size) : Rect{size,size} {}
void Print() const override {
cout << "Square:" <<w_<<"x"<<h_<<end; }
};
void Print(const Rect& rect) { rect.Print()}
int main(){
Print(Square(10)); Print(Rect(10,20));
return 0;
}
Example 2
#include <iostream>
using std::cout; using std::endl;
class Rect{
public:
Rect(int w, int h) : w_{w}, h_{h} {}
void Print(){
cout << "Rect: " << w_ << "x" <<h_ <<endl;
}
private:
int w_ = 0;
int h_ = 0;
};
struct Square : public Rect{ // abstract functionality
explicit Square(int size) : Rect{size,size} {}
};
int main(){
Square square(10);
square.Print();
return 0;
}
Example 3
#include <iostream>
using std::cout; using std::endl;
class Rect{
public:
Rect(int w, int h) : w_{w}, h_{h} {}
virtual void Print() const {
cout << "Rect: " << w_ << "x" <<h_ <<endl;
}
private:
int w_ = 0;
int h_ = 0;
};
class Square : public Rect{
public:
explicit Square(int size) : Rect{size,size} {} // 부모 개열의 데이터 베리어블을 끌어와 쓴다.
void Print() const override {
cout << "Square:" <<w_<<"x"<<h_<<end; }
};
int main(){
Square square(10);
const Rect& rect_ref = square;
rect_ref.Print();
return 0;
}
// output square 10x10
Using interfaces
- 모든 instance가 연결되어 있다.
- Use interfaces when you must enforce other classes to implement some functionality
- Allow thinking about classes in terms of abstract functionality(it has at laset pure virutal function but no implementation)
- Hide implementation from the caller
- Allow to easily extend functionality by simply adding a new class
#include <iostream>
using std::cout;
using std::endl;
struct Printable{
virtual void Print() const = 0; //Abstract functionlity: it has at least pure virutal function but no implementation
};
struct A : public Printable{
void Print() const override{cout << "A" << endl;}
};
struct B : public Printable{
void Print() const override{cout << "B" << endl;}
};
void Print(const Printable& val) {var.Print()}
int main(){
Print(A());
Print(B());
return 0;
}
Using strategy pattern
- If a class relies on complex external, functionality use strategy pattern
- Allows to add/switch functionality of the class without changing its implementation
- All strategies must conform to one strategy interface
#include <iostream>
using std::cout; using std::endl;
struct Strategy { // Saving space , should be classes.
virtual void Print () const = 0;
};
struct StrategyA : public Strategy{
void Print() const override {cout <<"A"<<endl;}
};
struct StrategyB : public Strategy{
void Print() const override {cout <<"B"<<endl;}
};
struct MyStruct{
MyStruct(const Strategy& s): strategy_(s) {}
void Print () const { strategy_ .Print (); }
const Strategy& strategy_;
}
int main () {
// Create a local var of MyStruct and call its Print
MyStruct(StrategyA()).Print ();
MyStruct(StrategyB()).Print ();
}
Do not overuse it
- Only use these patterns when you need to
- If your class should have a single method for some functionality and will never need another implementation don’t make it virtual
- Used mostly to avoid copying code and to make classes smaller by moving some functionality out
Reading and writing to files
- Use streams from STL
- Syntax similar to cerr, cout
#include <fstream>
using std::string;
using Mode = std::ios_base::openmode;
// ifstream: stream for input from file
std :: ifstream f_in(string& file_name , Mode mode);
// ofstream: stream for output to fil
std :: ofstream f_out(string& file_name , Mode mode);
// stream for input and output to file
std :: fstream f_in_out(string& file_name , Mode mode);
There are many modes under which a file can be opened
Regular columns
Use it when:
- The file constains organized data
- Every line has to have all columns
Reading from ifstream
#include <fstream> // For the file streams.
#include <iostream>
#include <string>
using namespace std; // Saving space.
int main () {
int i;
double a, b;
string s;
ifstream in("test_cols.txt", ios_base::in);
// Read data , until it is there.
while (in >> i >> a >> s >> b) {
cerr << i << ", " << a << ", "
<< s << ", " << b << endl;
}// print out from text file
return 0;
}
Reading files one line at a time
- Bind every line to a string
- Afterwards parse the string
#include <fstream> // For the file streams.
#include <iostream>
using namespace std; // Saving space.
int main () {
string line, file_name;
ifstream input("test_bel.txt", ios_base::in);
// Read data line -wise
while (getline(input , line)) {
cout << "Read: " << line << endl;
// String has a find method
string :: size_type loc = line.find("filename", 0);
if (loc != string :: npos) {
file_name = line.substr(line.find("=", 0) + 1,string :: npos);
}
}
cout << "Filename found: " << file_name << endl;
return 0;
}
Writing into text files
- With the same syntax as cerr and cout streams, with ofstream we can write directly into files
#include <iomanip> // For setprecision.
#include <fstream>
using namespace std;
int main(){
string filename = "out.txt";
ofstream outfile(filename);
if (!outfile.is_open ()) { return EXIT_FAILURE ; }
double a = 1.123123123;
outfile << "Just string" << endl; // write in the file directly
outfile << setprecision (20) << a << endl;
return 0;
}
String streams
Already known streams:
- Standard output: cerr, cout
- Standard input: cin
- Filestreams: fstream, ifstream, ofstream
New type of stream: stringstream
- Combine int, double, string, etc. into a single string
- Break up strings into int, double, string etc.
#include <iomanip>
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
stringstream s_out;
string ext = ".txt", file_name = "";
for (int i = 0; i < 500; ++i) {
// Combine variables into a stringstream.
s_out << setw (5) << setfill('0') << i << ext;
file_name = s_out.str (); // Get a string.
s_out.str(""); // Empty stream for next iteration.
cerr << file_name << endl;
}
stringstream s_in( file_name );
int i; string rest;
s_in >> i >> rest;
cerr << "Number: " << i << " rest is: " << rest;
return 0;
}
CMake find_path and find_library
- We can use an external library
- Need headers and binary library files
- There is an easy way to find them
Headers:
find_path(SOME_PKG_INCLUDE_DIR include/some_file .h
<path1 > <path2 > ...)
include_directories(${SOME_PKG_INCLUDE_DIR})
Libraries:
find_library(SOME_LIB
NAMES <some_lib >
PATHS <path1 > <path2 > ...)
target_link_libraries(target ${SOME_LIB})
find_package
- find_package calls multiple find_path and find_library functions
- To use find_package(
) CMake must have a file Find.cmake in MAKE_MODULE_PATH folders
- Find
.cmake defines which libraries and headers belong to package
- Pre-defined for most popular libraries, e.g. OpenCV, libpng, etc.
CMakeLists.txt
1 cmake_minimum_required(VERSION 2.8)
2 project( first_project )
3
4 # CMake will search here for Find <pkg >.cmake files
5 SET( CMAKE_MODULE_PATH
6 ${PROJECT_SOURCE_DIR}/ cmake_modules )
7
8 # Search for Findsome_pkg.cmake file and load it
9 find_package(some_pkg )
10
11 # Add the include folders from some_pkg
12 include_directories(${some_pkg_INCLUDE_DIRS})
13
14 # Add the executable "main"
15 add_executable(main small_main .cpp)
16 # Tell the linker to bind these binary objects
17 target_link_libraries(main ${some_pkg_LIBRARIES})
cmake_modules/Findsome_pkg.cmake
1 # Find the headers that we will need
2 find_path( some_pkg_INCLUDE_DIRS include/some_lib.h
3 <FOLDER_WHERE_TO_SEARCH >)
4 message(STATUS "headers: ${some_pkg_INCLUDE_DIRS}")
5
6 # Find the corresponding libraries
7 find_library( some_pkg_LIBRARIES
8 NAMES some_lib_name
9 PATHS <FOLDER_WHERE_TO_SEARCH >)
10 message(STATUS "libs: ${some_pkg_LIBRARIES}")
Reference
https://www.ipb.uni-bonn.de/teaching/modern-cpp/
Cpp Core Guidelines:
https://github.com/isocpp/CppCoreGuidelines
Git guide:
http://rogerdudler.github.io/git-guide/
C++ Tutorial:
http://www.cplusplus.com/doc/tutorial/
Book: Code Complete 2 by Steve McConnell
Modern CMake Tutorial
https://www.youtube.com/watch?v=eC9-iRN2b04
Compiler Explorer:
https://godbolt.org/
Gdbgui:
https://www.gdbgui.com/
CMake website:
https://cmake.org/
Gdbgui tutorial:
https://www.youtube.com/watch?v=em842geJhfk
Fluent C++: structs vs classes:
https://google.github.io/styleguide/cppguide.html#Structs_vs._Classes
Polymorphism(something take many shape)
- Allows morphing(变形) derived classes into their base class type:
- const Base& base = Derived(…)
- there are relationship between A and B
When is it useful?
- Allows encapsulating the implementation inside a class only asking it to conform to a common interface
- 즉 이미지 프로세싱에 있어 두가징 방법으로 같은 결과 구함(이미지 한장가지고 여러 가지 일을 함 : Canny detection , bitwise )
- Often used for:
- Working with all children of some Base class in unified(统一) manner
- Enforcing an interface in multiple classes to force them to implement some functionality
- In strategy pattern, where some complex functionality is outsourced into separate classes and is passed to the object in a modular fashion
- image class we want to save two difference processed picture.
Creating a class hierarchy
- Sometimes classes must form a hierarchy
- Distinguish between is a and has a to test if the classes should be in one hierarchy:
- Square is a Shape: can inherit from Shape
- Student is a Human: can inherit from Human
- Car has a Wheel: should not inherit each other
- Prefer shallow hierarchies
- GOOGLE-STYLE Prefer composition, i.e. including an object of another class as a member of your class
Example 1
#include <iostream>
using std::cout; using std::endl;
class Rect{
public:
Rect(int w, int h) : w_{w}, h_{h} {}
virtual void Print() const {
cout << "Rect: " << w_ << "x" <<h_ <<endl;
}
private:
int w_ = 0;
int h_ = 0;
};
struct Square : public Rect{
explicit Square(int size) : Rect{size,size} {}
void Print() const override {
cout << "Square:" <<w_<<"x"<<h_<<end; }
};
void Print(const Rect& rect) { rect.Print()}
int main(){
Print(Square(10)); Print(Rect(10,20));
return 0;
}
Example 2
#include <iostream>
using std::cout; using std::endl;
class Rect{
public:
Rect(int w, int h) : w_{w}, h_{h} {}
void Print(){
cout << "Rect: " << w_ << "x" <<h_ <<endl;
}
private:
int w_ = 0;
int h_ = 0;
};
struct Square : public Rect{ // abstract functionality
explicit Square(int size) : Rect{size,size} {}
};
int main(){
Square square(10);
square.Print();
return 0;
}
Example 3
#include <iostream>
using std::cout; using std::endl;
class Rect{
public:
Rect(int w, int h) : w_{w}, h_{h} {}
virtual void Print() const {
cout << "Rect: " << w_ << "x" <<h_ <<endl;
}
private:
int w_ = 0;
int h_ = 0;
};
class Square : public Rect{
public:
explicit Square(int size) : Rect{size,size} {} // 부모 개열의 데이터 베리어블을 끌어와 쓴다.
void Print() const override {
cout << "Square:" <<w_<<"x"<<h_<<end; }
};
int main(){
Square square(10);
const Rect& rect_ref = square;
rect_ref.Print();
return 0;
}
// output square 10x10
Using interfaces
- 모든 instance가 연결되어 있다.
- Use interfaces when you must enforce other classes to implement some functionality
- Allow thinking about classes in terms of abstract functionality(it has at laset pure virutal function but no implementation)
- Hide implementation from the caller
- Allow to easily extend functionality by simply adding a new class
#include <iostream>
using std::cout;
using std::endl;
struct Printable{
virtual void Print() const = 0; //Abstract functionlity: it has at least pure virutal function but no implementation
};
struct A : public Printable{
void Print() const override{cout << "A" << endl;}
};
struct B : public Printable{
void Print() const override{cout << "B" << endl;}
};
void Print(const Printable& val) {var.Print()}
int main(){
Print(A());
Print(B());
return 0;
}
Using strategy pattern
- If a class relies on complex external, functionality use strategy pattern
- Allows to add/switch functionality of the class without changing its implementation
- All strategies must conform to one strategy interface
#include <iostream> using std::cout; using std::endl; struct Strategy { // Saving space , should be classes. virtual void Print () const = 0; }; struct StrategyA : public Strategy{ void Print() const override {cout <<"A"<<endl;} }; struct StrategyB : public Strategy{ void Print() const override {cout <<"B"<<endl;} }; struct MyStruct{ MyStruct(const Strategy& s): strategy_(s) {} void Print () const { strategy_ .Print (); } const Strategy& strategy_; } int main () { // Create a local var of MyStruct and call its Print MyStruct(StrategyA()).Print (); MyStruct(StrategyB()).Print (); }
Do not overuse it
- Only use these patterns when you need to
- If your class should have a single method for some functionality and will never need another implementation don’t make it virtual
- Used mostly to avoid copying code and to make classes smaller by moving some functionality out
Reading and writing to files
- Use streams from STL
- Syntax similar to cerr, cout
#include <fstream>
using std::string;
using Mode = std::ios_base::openmode;
// ifstream: stream for input from file
std :: ifstream f_in(string& file_name , Mode mode);
// ofstream: stream for output to fil
std :: ofstream f_out(string& file_name , Mode mode);
// stream for input and output to file
std :: fstream f_in_out(string& file_name , Mode mode);
There are many modes under which a file can be opened
Regular columns
Use it when:
- The file constains organized data
- Every line has to have all columns
Reading from ifstream
#include <fstream> // For the file streams.
#include <iostream>
#include <string>
using namespace std; // Saving space.
int main () {
int i;
double a, b;
string s;
ifstream in("test_cols.txt", ios_base::in);
// Read data , until it is there.
while (in >> i >> a >> s >> b) {
cerr << i << ", " << a << ", "
<< s << ", " << b << endl;
}// print out from text file
return 0;
}
Reading files one line at a time
- Bind every line to a string
- Afterwards parse the string
#include <fstream> // For the file streams.
#include <iostream>
using namespace std; // Saving space.
int main () {
string line, file_name;
ifstream input("test_bel.txt", ios_base::in);
// Read data line -wise
while (getline(input , line)) {
cout << "Read: " << line << endl;
// String has a find method
string :: size_type loc = line.find("filename", 0);
if (loc != string :: npos) {
file_name = line.substr(line.find("=", 0) + 1,string :: npos);
}
}
cout << "Filename found: " << file_name << endl;
return 0;
}
Writing into text files
- With the same syntax as cerr and cout streams, with ofstream we can write directly into files
#include <iomanip> // For setprecision. #include <fstream> using namespace std; int main(){ string filename = "out.txt"; ofstream outfile(filename); if (!outfile.is_open ()) { return EXIT_FAILURE ; } double a = 1.123123123; outfile << "Just string" << endl; // write in the file directly outfile << setprecision (20) << a << endl; return 0; }
String streams
Already known streams:
- Standard output: cerr, cout
- Standard input: cin
- Filestreams: fstream, ifstream, ofstream
New type of stream: stringstream
- Combine int, double, string, etc. into a single string
- Break up strings into int, double, string etc.
#include <iomanip> #include <iostream> #include <sstream> using namespace std; int main() { stringstream s_out; string ext = ".txt", file_name = ""; for (int i = 0; i < 500; ++i) { // Combine variables into a stringstream. s_out << setw (5) << setfill('0') << i << ext; file_name = s_out.str (); // Get a string. s_out.str(""); // Empty stream for next iteration. cerr << file_name << endl; } stringstream s_in( file_name ); int i; string rest; s_in >> i >> rest; cerr << "Number: " << i << " rest is: " << rest; return 0; }
CMake find_path and find_library
- We can use an external library
- Need headers and binary library files
- There is an easy way to find them
Headers:
find_path(SOME_PKG_INCLUDE_DIR include/some_file .h
<path1 > <path2 > ...)
include_directories(${SOME_PKG_INCLUDE_DIR})
Libraries:
find_library(SOME_LIB
NAMES <some_lib >
PATHS <path1 > <path2 > ...)
target_link_libraries(target ${SOME_LIB})
find_package
- find_package calls multiple find_path and find_library functions
- To use find_package(
) CMake must have a file Find .cmake in MAKE_MODULE_PATH folders - Find
.cmake defines which libraries and headers belong to package - Pre-defined for most popular libraries, e.g. OpenCV, libpng, etc.
CMakeLists.txt
1 cmake_minimum_required(VERSION 2.8)
2 project( first_project )
3
4 # CMake will search here for Find <pkg >.cmake files
5 SET( CMAKE_MODULE_PATH
6 ${PROJECT_SOURCE_DIR}/ cmake_modules )
7
8 # Search for Findsome_pkg.cmake file and load it
9 find_package(some_pkg )
10
11 # Add the include folders from some_pkg
12 include_directories(${some_pkg_INCLUDE_DIRS})
13
14 # Add the executable "main"
15 add_executable(main small_main .cpp)
16 # Tell the linker to bind these binary objects
17 target_link_libraries(main ${some_pkg_LIBRARIES})
cmake_modules/Findsome_pkg.cmake
1 # Find the headers that we will need
2 find_path( some_pkg_INCLUDE_DIRS include/some_lib.h
3 <FOLDER_WHERE_TO_SEARCH >)
4 message(STATUS "headers: ${some_pkg_INCLUDE_DIRS}")
5
6 # Find the corresponding libraries
7 find_library( some_pkg_LIBRARIES
8 NAMES some_lib_name
9 PATHS <FOLDER_WHERE_TO_SEARCH >)
10 message(STATUS "libs: ${some_pkg_LIBRARIES}")
Reference
https://www.ipb.uni-bonn.de/teaching/modern-cpp/
Cpp Core Guidelines: https://github.com/isocpp/CppCoreGuidelines
Git guide: http://rogerdudler.github.io/git-guide/
C++ Tutorial: http://www.cplusplus.com/doc/tutorial/
Book: Code Complete 2 by Steve McConnell
Modern CMake Tutorial https://www.youtube.com/watch?v=eC9-iRN2b04
Compiler Explorer: https://godbolt.org/ Gdbgui: https://www.gdbgui.com/ CMake website: https://cmake.org/ Gdbgui tutorial: https://www.youtube.com/watch?v=em842geJhfk
Fluent C++: structs vs classes: https://google.github.io/styleguide/cppguide.html#Structs_vs._Classes
Comments