OOP Complementary Topics

Video

Struct vs Class

  • struct is default public
  • class is default private

👌 C++ struct, short for C++ Structure, is a user-defined data type available in C++. It allows users to combine data items of (possibly) different data types under a single name.

Run in Repl.it https://repl.it/join/qhyexqcp-maikolguzman

C++
#include <iostream>  // allows program to output data to the screen

struct Base {
public:
    int numA = 0;
protected:
    int numB = 1;
protected:
    int numC = 2;
};

struct Derived: public Base {
    Derived() {
        numA = 3;
    }
public:
    int numD = 3;
protected:
    int numE = 4;
private:
    int numF = 5;
};

// function main begins program execution
int main(int argc, const char *argv[]) {
    std::cout << "Welcome to the UNA!" << std::endl;  // display message

    Derived derived;
    derived.numA = 100;

    return 0;  // indicate that program ended successfully
}  // end function main

Virtual Functions

📌 We can create programs with different behaviors in runtime, taking advantage of runtime polymorphism.

  • virtual is used to create methods that are chosen at runtime
  • When a method is declared virtual, the most derived version of that method is executed at runtime
  • Extra time cost for the CPU
  • If a member of a derived class matches the signature of the member in a base class, the derived method is automatically virtual.

Run in Repl.it https://repl.it/@MaikolGuzman/virtual-01-basic

C++
#include <iostream>  // allows program to output data to the screen

struct Base {
    virtual int get() const {
      return 4;
    }

    /*int get() const {
      return 4;
    }*/
};

struct Derived : Base {
    int get() const {
      return 1;
    }
};

int get(const Base &b) {
  return b.get();
}

// function main begins program execution
int main(int argc, const char *argv[]) {
    std::cout << "Welcome to the UNA! (VIRTUAL)" << std::endl;  // display message

  Derived derived;
  
  return get(derived);
}  // end function main

Pure virtual functions

Functions declared with this signature are called “Pure Virtual”.

C++
virtual int get() const = 0;

Virtual Destructors

  • Destructors can be declared virtual
  • Like regular member functions, virtual destructors ensure that the most derived version is called
  • Also, like regular member functions, virtual destructors only come in to play if you access an object via a pointer to a base class (example deleting it)
  • If a base class destructor is virtual, so is the automatically created derived class destructor

Run in Repl.it https://repl.it/@MaikolGuzman/virtual-03-destructors

C++
#include <iostream>  // allows program to output data to the screen

struct Base {
  virtual ~Base() {
    std::cout << "~Base()\n";
  }
  /*~Base() {
    std::cout << "~Base()\n";
  }*/
};

struct Derived : Base {
  ~Derived() {
    std::cout << "~Derived()\n";
  }
};

// function main begins program execution
int main(int argc, const char *argv[]) {
  std::cout << "Welcome to the UNA! (VIRTUAL)" << std::endl;

  Base *base = new Derived();
  
  delete base; // what is printed here?
}  // end function main

Abstract Classes

  • Any class with unimplemented pure virtual functions is an “abstract class”
  • Abstract classes cannot be initialized.

Run in Repl.it https://repl.it/@MaikolGuzman/virtual-02-abstract-class

C++
#include <iostream>  // allows program to output data to the screen

struct Base {
  virtual void doSomething() = 0;
};

struct Derived : Base {
  void doSomething() {
    
  }
};

// function main begins program execution
int main(int argc, const char *argv[]) {
  std::cout << "Welcome to the UNA! (VIRTUAL)" << std::endl;

  Derived derived;
}  // end function main

Override

  • override tells the compiler that you are intending to change the behavior of a method in a base class
  • If a function marked as override does not properly override an existing virtual function in a base class, a compile-time error is thrown.

Run in Repl.it https://repl.it/@MaikolGuzman/override-01-base

C++
#include <iostream>  // allows program to output data to the screen

struct Base {
  virtual void doSomething() const {
  }
};

struct Derived : Base {
  void doSomething() const override {
    std::cout << "Hola Mike!!!" << std::endl;
  }
};

// function main begins program execution
int main(int argc, const char *argv[]) {
  std::cout << "Welcome to the UNA! (VIRTUAL)" << std::endl;

  Derived derived;

  derived.doSomething();
  
}  // end function main

Final

  • final can be applied to either methods or classes.
  • A class marked final cannot be further inherited from.
  • A method marked final cannot be further overridden.
  • If a function marked as final does not properly override an existing virtual function, a compile-time error is thrown.

Run in Repl.it https://repl.it/@MaikolGuzman/override-02-final

C++
#include <iostream>  // allows program to output data to the screen

struct Base {
  virtual void doSomething() const {
  }
};

struct Intermediate : Base {
  void doSomething() const final {
    std::cout << "Hola Intermedio!!!" << std::endl;
  }
};

struct Derived : Intermediate {
  /*void doSomething() const override {
    std::cout << "Hola Mike!!!" << std::endl;
  }*/
};

// function main begins program execution
int main(int argc, const char *argv[]) {
  std::cout << "Welcome to the UNA! (VIRTUAL)" << std::endl;

  Derived derived;

  derived.doSomething();
  
}  // end function main

📌 Best Practices

  • Only define a destructor if you must
  • Always define a virtual destructor if you have a virtual function (the compiler will warn you).