Я изучаю сложный способ нарезки объектов, и мне интересно, возможно ли когда-либо указатель быть нарезанным на объекте. Другими словами:
Да — указатель на base
требуется, чтобы иметь возможность ссылаться на объект любого типа, полученный из base
и по-прежнему сохраняют правильный тип для производного объекта (и для чего бы это ни стоило, то же самое верно и для ссылок).
Это зависит от того, насколько свободно вы хотите определить «нарезку». В некотором смысле, когда вы указываете на производный объект с базовым указателем (или ссылкой), любые не виртуальные функции будут разделены. Например:
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"
Призыв к DoB
не работает, потому что мы используем указатель на A
так что компилятор не знает, что он может вызвать DoB
на этот указатель. Таким образом, вы теряете часть B
, так что вы можете думать об этом как о форме нарезки.
В частности, последняя строка является примером явления, называемого «сокрытие имени». Так как Print
не был объявлен virtual
в базовом классе, и наш указатель имеет тип A
, компилятор не знает, что он должен вызывать B::Print
вместо A::Print
,
Важный пример этой проблемы вступает в игру с вашим деструктором:
class A {
~A() {}
};
class B : public A {
std::vector<int> v;
};
A* a = new B;
delete a; // What happens to B::v? Undefined behaviour!
Здесь, потому что деструктор не был отмечен как virtual
называется деструктором базового класса в не виртуальном контексте, что означает B
Деструктор не будет вызван.