https://www.youtube.com/watch?v=_go74QpFPAw

https://www.youtube.com/watch?v=SuubuqI4gVA

Objects

order of construction

object is constructed in this order: 1) its virtual base gets constructed, 2) then its base, 3) then its members, 4) then the constructor body runs

destruction order is in the exact reverse order

Object slicing

Definition: when an object of subclass type is copied to the superclass type, the superclass object has no details of member variables and functions of subclass type. These member variables and functions are, in effect, sliced off.

Consider the following example:

class Base {
  virtual std::string_view getName() const { return "Base"; }
};

class Derived: public Base {
  std::string_view getName() const override { return "Derived"; }
}

int main() {
  Derived derived;

  // derived object has 2 parts: Base part and Derived part
  // b1 and b2 can only see Base part,
  // but through virtual functions, they can use the logic of
  // the most derived functions
  Base &b1 = derived;
  Base *b2 = &derived;
  std::cout << b1.getName();
  std::cout << b2->getName(); // both print “Derived”

  // but b3 here can only see the Base part, so only the Base part is copied
  // Derived part is sliced off
  Base b3 = derived;
  std::cout << b3.getName(); // print “Base”;
}

Frakenobject

Object slicing might lead to an object composed of parts from different objects.

For example:

Derived d1;
Derived d2;
Base &b = d1;

// here normally one expects the same as d1 = d2;
// however, as b can only see Base part and operator= is not virtual by default,
// only Base part is copied!
// => d1 now will have Base part from d2 but Derived part from d1!
b = d2;

Virtual constructor and destructor

Object slicing also applies to construct and destructor!

class Dog {
  Dog() { std::cout << "Dog" << std::endl; } 
  Dog(const Dog&) { std::cout << "copy Dog" << std::endl; }
  ~Dog() { std::cout << "destroy Dog" << std::endl; }
};

class YellowDog: public Dog {
  YellowDog() { std::cout << "YellowDog" << std::endl; } 
  YellowDog(const YellowDog&) { std::cout << "copy YellowDog" << std::endl; }
  ~YellowDog() { std::cout << "destroy YellowDog" << std::endl; }
};

int main() {
  Dog *dog = new YellowDog(); // object slicing
  Dog dog1 = *dog; // prints "copy Dog"
  delete dog; // prints "destroy Dog"
  // sliced object has type Dog
  // => only see Dog() copy constructor and destructor!
}

The fix is to use virtual constructors and destructors…