for Robot Artificial Inteligence

6. polymorphism, I/O, String streams, Cmake find_package

|

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