在c++中,什么是对象切片,什么时候发生?


当前回答

所以为什么丢失派生信息很糟糕。。。因为派生类的作者可能已经改变了表示方式,使得分割额外信息改变了对象所表示的值。如果派生类用于缓存对某些操作更有效但转换回基表示代价高昂的表示,则会发生这种情况。

还认为有人应该提到你应该做什么来避免切片。。。获取C++编码标准、101条规则指南和最佳实践的副本。处理切片是#54。

它提出了一种有点复杂的模式来完全解决这个问题:有一个受保护的复制构造函数、一个受受保护的纯虚拟DoClone,以及一个带有断言的公共克隆,如果(进一步)派生类未能正确实现DoClone,该断言将告诉您。(克隆方法对多态对象进行适当的深度复制。)

您还可以在基显式上标记复制构造函数,如果需要,它允许显式切片。

其他回答

在C++中,派生类对象可以分配给基类对象,但另一种方式是不可能的。

class Base { int x, y; };

class Derived : public Base { int z, w; };

int main() 
{
    Derived d;
    Base b = d; // Object Slicing,  z and w of d are sliced off
}

当派生类对象分配给基类对象时,对象切片发生,派生类对象的其他属性被切片以形成基类对象。

谷歌第三次匹配“C++切片”给了我这篇维基百科文章http://en.wikipedia.org/wiki/Object_slicing这(很热,但前几篇文章定义了问题):http://bytes.com/forum/thread163565.html

因此,当您将子类的对象分配给超级类时。超类对子类中的附加信息一无所知,并且没有空间存储它,因此附加信息被“分割”。

如果这些链接没有提供足够的信息来获得“好答案”,请编辑您的问题,让我们知道您还需要什么。

1.切片问题的定义

如果D是基类B的派生类,则可以将派生类型的对象分配给base类型的变量(或参数)。

例子

class Pet
{
 public:
    string name;
};
class Dog : public Pet
{
public:
    string breed;
};

int main()
{   
    Dog dog;
    Pet pet;

    dog.name = "Tommy";
    dog.breed = "Kangal Dog";
    pet = dog;
    cout << pet.breed; //ERROR

尽管上面的赋值是允许的,但赋值给变量宠物的值将丢失其品种字段。这被称为切片问题。

2.如何解决切片问题

为了解决这个问题,我们使用指向动态变量的指针。

例子

Pet *ptrP;
Dog *ptrD;
ptrD = new Dog;         
ptrD->name = "Tommy";
ptrD->breed = "Kangal Dog";
ptrP = ptrD;
cout << ((Dog *)ptrP)->breed; 

在这种情况下,没有动态变量的数据成员或成员函数被ptrD(后代类对象)指向的对象将丢失。此外,如果需要使用函数,则函数必须是虚拟函数。

C++中的切片问题源于其对象的值语义,这主要是由于与C结构的兼容性。您需要使用显式引用或指针语法来实现大多数其他语言中的“正常”对象行为,即对象总是通过引用传递。

简单的答案是,通过按值将派生对象分配给基础对象来切片对象,即,剩余对象只是派生对象的一部分。为了保持值语义,切片是一种合理的行为,其用途相对较少,这在大多数其他语言中都不存在。有些人认为它是C++的一个特性,而许多人则认为这是C++的怪癖/错误特性之一。

在我看来,除了你自己的类和程序架构/设计不好之外,切片并不是什么问题。

如果我将一个子类对象作为参数传递给一个方法,该方法接受一个超类类型的参数,那么我当然应该意识到这一点,并且知道在内部,被调用的方法只能使用超类(也称为基类)对象。

在我看来,提供一个请求基类的子类会导致子类特定的结果,这似乎只是一个不合理的期望,会导致切片成为一个问题。它要么在方法的使用上设计糟糕,要么子类实现糟糕。我猜这通常是牺牲了良好的OOP设计,而为了方便或提高性能的结果。