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


当前回答

切片问题很严重,因为它会导致内存损坏,而且很难保证程序不会受到这种问题的困扰。要用语言设计它,支持继承的类应该只能通过引用(而不是通过值)访问。D编程语言具有此属性。

考虑从A派生的类A和类B。如果A部分有一个指针p,而B实例指向B的附加数据,则可能发生内存损坏。然后,当附加数据被切片时,p指向垃圾。

其他回答

我看到所有的答案都提到了当数据成员被切片时对象切片发生的情况。这里我举了一个示例,说明这些方法不会被重写:

class A{
public:
    virtual void Say(){
        std::cout<<"I am A"<<std::endl;
    }
};

class B: public A{
public:
    void Say() override{
        std::cout<<"I am B"<<std::endl;
    }
};

int main(){
   B b;
   A a1;
   A a2=b;

   b.Say(); // I am B
   a1.Say(); // I am A
   a2.Say(); // I am A   why???
}

B(对象B)从A(对象a1和a2)导出。正如我们所期望的,b和a1调用它们的成员函数。但从多态性的角度来看,我们不期望由b赋值的a2不会被重写。基本上,a2只保存b的A类部分,即C++中的对象切片。

要解决此问题,应使用引用或指针

 A& a2=b;
 a2.Say(); // I am B

or

A* a2 = &b;
a2->Say(); // I am B

谷歌第三次匹配“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(后代类对象)指向的对象将丢失。此外,如果需要使用函数,则函数必须是虚拟函数。

切片意味着当子类的对象通过值或从期望基类对象的函数传递或返回时,子类添加的数据将被丢弃。

说明:考虑以下类声明:

           class baseclass
          {
                 ...
                 baseclass & operator =(const baseclass&);
                 baseclass(const baseclass&);
          }
          void function( )
          {
                baseclass obj1=m;
                obj1=m;
          }

由于基类复制函数不知道派生的任何信息,因此只复制派生的基部分。这通常被称为切片。

在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
}

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