2013-06-05 79 views
0

我正在学习关于对象切片的难题,我想知道是否有可能对指针进行对象切片。换句话说:指针和对象切片

  • 指针可以是对象切片的受害者,或者只要您使用指针,您总是可以安全地使用对象切片?
+1

你可能会从这里学到最好的:http://stackoverflow.com/questions/274626/what-is-the-slicing-problem-in-c – chris

+3

我喜欢你如何提出矛盾的问题'指针可以是对象切片的受害者?'和'只要你使用了一个指针,你总是可以避免对象切片?'。这使得答案混淆。 – milleniumbug

回答

3

是 - 指针base需要能够指从base派生的任何类型的对象,并仍保持正确的类型派生对象(以及它的价值,也是同样的道理与参考)。

+3

“是的,它总是安全的。”他的问题承认不是“是”或“否”的答案。 –

7

这取决于你是否愿意定义“切片”的松散程度。从某种意义上讲,当你指向一个带有基指针(或引用)的派生对象时,任何非虚函数都会被切分。例如:

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" 

,因为我们使用的指针A,所以编译器不知道它可以对指针调用DoBDoB调用不起作用。这样,你就失去了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的析构函数不会被调用。

+0

哇,这是一个很好的答案。非常丰富。谢谢! –