在c++中,什么是对象切片,什么时候发生?
当前回答
我刚刚遇到了切片问题,很快就到了这里。所以让我再加上两美分。
让我们来举一个“生产代码”(或类似代码)的例子:
假设我们有一个可以调度动作的东西。例如,控制中心UI。此UI需要获取当前可以调度的事物的列表。因此,我们定义了一个包含分派信息的类。让我们称之为行动。因此,Action有一些成员变量。为了简单起见,我们只有2,即std::string名称和std::function<void()>f。然后它有一个void activate(),它只执行f成员。
因此,UI得到了一个std::vector<Action>。设想一些功能,如:
void push_back(Action toAdd);
现在,我们已经从UI的角度确定了它的外观。到目前为止没有问题。但是另一个从事这个项目的人突然决定,Action对象中有一些特殊的动作需要更多的信息。无论出于什么原因。这也可以通过lambda捕获来解决。此示例并非取自代码1-1。
所以这家伙从《行动》中派生出来,以增添自己的味道。他将自己制作的课程的一个实例传递给push_back,但随后程序就失控了。
那发生了什么?正如您可能已经猜到的:对象已被切片。
实例中的额外信息已经丢失,f现在容易出现未定义的行为。
我希望这个例子能给那些在谈论以某种方式派生的A和B时无法真正想象事情的人带来启发。
其他回答
C++中的切片问题源于其对象的值语义,这主要是由于与C结构的兼容性。您需要使用显式引用或指针语法来实现大多数其他语言中的“正常”对象行为,即对象总是通过引用传递。
简单的答案是,通过按值将派生对象分配给基础对象来切片对象,即,剩余对象只是派生对象的一部分。为了保持值语义,切片是一种合理的行为,其用途相对较少,这在大多数其他语言中都不存在。有些人认为它是C++的一个特性,而许多人则认为这是C++的怪癖/错误特性之一。
如果您有一个基类a和一个派生类B,那么您可以执行以下操作。
void wantAnA(A myA)
{
// work with myA
}
B derived;
// work with the object "derived"
wantAnA(derived);
现在,方法wantAnA需要派生的副本。然而,派生的对象不能完全复制,因为类B可以创建不在其基类A中的其他成员变量。
因此,要调用wantAnA,编译器将“切片”派生类的所有其他成员。结果可能是您不想创建的对象,因为
它可能是不完整的,它的行为类似于A对象(B类的所有特殊行为都丢失了)。
当派生类对象分配给基类对象时,派生类对象的所有成员都将复制到基类对象,但基类中不存在的成员除外。这些成员被编译器切片。这称为对象切片。
下面是一个示例:
#include<bits/stdc++.h>
using namespace std;
class Base
{
public:
int a;
int b;
int c;
Base()
{
a=10;
b=20;
c=30;
}
};
class Derived : public Base
{
public:
int d;
int e;
Derived()
{
d=40;
e=50;
}
};
int main()
{
Derived d;
cout<<d.a<<"\n";
cout<<d.b<<"\n";
cout<<d.c<<"\n";
cout<<d.d<<"\n";
cout<<d.e<<"\n";
Base b = d;
cout<<b.a<<"\n";
cout<<b.b<<"\n";
cout<<b.c<<"\n";
cout<<b.d<<"\n";
cout<<b.e<<"\n";
return 0;
}
它将产生:
[Error] 'class Base' has no member named 'd'
[Error] 'class Base' has no member named 'e'
当派生类对象被分配给基类对象时,派生类对象的其他属性将从基类对象中切下(丢弃)。
class Base {
int x;
};
class Derived : public Base {
int z;
};
int main()
{
Derived d;
Base b = d; // Object Slicing, z of d is sliced off
}
在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
}
当派生类对象分配给基类对象时,对象切片发生,派生类对象的其他属性被切片以形成基类对象。