我正在学习关于对象切片的艰难方法,我想知道指针是否有可能被对象切片。换句话说:
答案 0 :(得分:12)
这取决于你愿意定义“切片”的程度。从某种意义上说,当您使用基指针(或引用)指向派生对象时,任何非虚函数都会被切片。例如:
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
而不是{ {1}}。
这个问题的一个重要例子与你的析构函数一起发挥作用:
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
的析构函数不会被调用。
答案 1 :(得分:3)
是的 - 指向base
的指针需要能够引用从base
派生的任何类型的对象,并且仍然保留派生对象的正确类型(以及它的价值) ,参考文献也是如此。