在c++中,什么是对象切片,什么时候发生?
当前回答
这些都是很好的答案。我只想在按值传递对象与按引用传递对象时添加一个执行示例:
#include <iostream>
using namespace std;
// Base class
class A {
public:
A() {}
A(const A& a) {
cout << "'A' copy constructor" << endl;
}
virtual void run() const { cout << "I am an 'A'" << endl; }
};
// Derived class
class B: public A {
public:
B():A() {}
B(const B& a):A(a) {
cout << "'B' copy constructor" << endl;
}
virtual void run() const { cout << "I am a 'B'" << endl; }
};
void g(const A & a) {
a.run();
}
void h(const A a) {
a.run();
}
int main() {
cout << "Call by reference" << endl;
g(B());
cout << endl << "Call by copy" << endl;
h(B());
}
输出为:
Call by reference
I am a 'B'
Call by copy
'A' copy constructor
I am an 'A'
其他回答
谷歌第三次匹配“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 A {
int foo;
};
class B : public A {
int bar;
};
因此,类型B的对象有两个数据成员,foo和bar。
那么如果你要写这个:
B b;
A a = b;
然后b中关于成员栏的信息在a中丢失。
切片意味着当子类的对象通过值或从期望基类对象的函数传递或返回时,子类添加的数据将被丢弃。
说明:考虑以下类声明:
class baseclass
{
...
baseclass & operator =(const baseclass&);
baseclass(const baseclass&);
}
void function( )
{
baseclass obj1=m;
obj1=m;
}
由于基类复制函数不知道派生的任何信息,因此只复制派生的基部分。这通常被称为切片。
如果您有一个基类a和一个派生类B,那么您可以执行以下操作。
void wantAnA(A myA)
{
// work with myA
}
B derived;
// work with the object "derived"
wantAnA(derived);
现在,方法wantAnA需要派生的副本。然而,派生的对象不能完全复制,因为类B可以创建不在其基类A中的其他成员变量。
因此,要调用wantAnA,编译器将“切片”派生类的所有其他成员。结果可能是您不想创建的对象,因为
它可能是不完整的,它的行为类似于A对象(B类的所有特殊行为都丢失了)。