It depends on how loosely you're willing to define "slicing". In a sense, when you point to a derived object with a base pointer (or reference), any non-virtual functions get sliced. For instance:
class A {
void Print() { cout << "Class A\n"; }
};
class B : public A {
void DoB() {}
void Print() { cout << "Class B\n"; }
};
B b;
A* a = &b;
a->DoB(); // Won't compile!
a->Print(); // Prints "Class A", not "Class B"
The call to DoB
doesn't work because we're using a pointer to an A
, so the compiler doesn't know it can call DoB
on that pointer. In this way, you're losing part of B
, so you can think of this as a form of slicing.
The last line in particular is an example of a phenomenon called "name hiding". Because Print
wasn't declared virtual
in the base class, and our pointer is of type A
, the compiler doesn't know that it should call B::Print
instead of A::Print
.
An important example of this problem comes into play with your destructor:
class A {
~A() {}
};
class B : public A {
std::vector<int> v;
};
A* a = new B;
delete a; // What happens to B::v? Undefined behaviour!
Here, because the destructor wasn't marked as virtual
, it called the base class's destructor in a non-virtual context, which means B
's destructor won't get called.