…
https://www.youtube.com/watch?v=_go74QpFPAw
https://www.youtube.com/watch?v=SuubuqI4gVA
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
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”;
}
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;
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…