C++ 什么是对象切片?
有人在IRC中提到它是切片问题。谷歌中第三个匹配的“C++切片”给了我这篇维基百科文章和这篇文章(很热,但前几篇文章定义了这个问题): 所以当你把一个子类的一个对象分配给超类时。超类对子类中的附加信息一无所知,并且没有空间存储它,因此附加信息被“切掉” 如果这些链接没有提供足够的信息来获得“好的答案”,请编辑您的问题,让我们知道您还需要什么。谷歌中第三个匹配的“C++切片”为我提供了这篇维基百科文章和这篇文章(热门,但前几篇文章定义了问题): 所以当你把一个子类的一个对象分配给超类时。超类对子类中的附加信息一无所知,并且没有空间存储它,因此附加信息被“切掉” 如果这些链接没有提供足够的信息来回答“好的答案”,请编辑您的问题,让我们知道您还需要什么。“切片”是指您将派生类的对象分配给基类的实例,从而丢失部分信息-其中一些信息被“切片”掉 比如说,C++ 什么是对象切片?,c++,inheritance,c++-faq,object-slicing,C++,Inheritance,C++ Faq,Object Slicing,有人在IRC中提到它是切片问题。谷歌中第三个匹配的“C++切片”给了我这篇维基百科文章和这篇文章(很热,但前几篇文章定义了这个问题): 所以当你把一个子类的一个对象分配给超类时。超类对子类中的附加信息一无所知,并且没有空间存储它,因此附加信息被“切掉” 如果这些链接没有提供足够的信息来获得“好的答案”,请编辑您的问题,让我们知道您还需要什么。谷歌中第三个匹配的“C++切片”为我提供了这篇维基百科文章和这篇文章(热门,但前几篇文章定义了问题): 所以当你把一个子类的一个对象分配给超类时。超类对子类
class A {
int foo;
};
class B : public A {
int bar;
};
因此,B
类型的对象有两个数据成员,foo
和bar
那么如果你要写这个:
B b;
A a = b;
然后b
中关于成员bar
的信息在a中丢失。“切片”是指将派生类的对象分配给基类的实例,从而丢失部分信息-其中一些信息被“切片”掉
比如说,
class A {
int foo;
};
class B : public A {
int bar;
};
因此,B
类型的对象有两个数据成员,foo
和bar
那么如果你要写这个:
B b;
A a = b;
然后b
中关于成员bar
的信息将丢失在a中。如果您有基类a
和派生类b
,则可以执行以下操作
void wantAnA(A myA)
{
// work with myA
}
B derived;
// work with the object "derived"
wantAnA(derived);
现在,方法wantAnA
需要一份derived
的副本。但是,派生的对象不能完全复制,因为类B
可以创建不在其基类A
中的其他成员变量
因此,要调用wantAnA
,编译器将“切掉”派生类的所有其他成员。结果可能是您不想创建的对象,因为
- 它可能是不完整的
- 它的行为类似于
A
-对象(类B
的所有特殊行为都将丢失)
如果您有一个基类a
和一个派生类B
,那么您可以执行以下操作
void wantAnA(A myA)
{
// work with myA
}
B derived;
// work with the object "derived"
wantAnA(derived);
现在,方法wantAnA
需要一份derived
的副本。但是,派生的对象不能完全复制,因为类B
可以创建不在其基类A
中的其他成员变量
因此,要调用wantAnA
,编译器将“切掉”派生类的所有其他成员。结果可能是您不想创建的对象,因为
- 它可能是不完整的
- 它的行为类似于
A
-对象(类B
的所有特殊行为都将丢失)
切片问题很严重,因为它会导致内存损坏,并且很难保证程序不会受到损坏。要在语言之外进行设计,支持继承的类应该只能通过引用(而不是通过值)进行访问。D编程语言具有这个特性
考虑从A派生的类A和类B。如果A部件具有指针p,并且B实例将p指向B的附加数据,则可能发生内存损坏。然后,当附加数据被切分时,p指向垃圾。切分问题很严重,因为它会导致内存损坏,并且很难保证程序不会受到损坏。要在语言之外进行设计,支持继承的类应该只能通过引用(而不是通过值)进行访问。D编程语言具有这个特性
考虑从A派生的类A和类B。如果A部件具有指针p,并且B实例将p指向B的附加数据,则可能发生内存损坏。然后,当附加数据被切掉时,p指向垃圾。。。。为什么丢失派生信息是不好的。。。因为派生类的作者可能已经更改了表示形式,因此切掉额外信息会更改对象表示的值。如果派生类用于缓存对某些操作更有效但转换回基表示代价高昂的表示,则可能发生这种情况
我还认为有人应该提到你应该做些什么来避免切片。。。
获取C++编码标准的副本,101条规则指南和最佳实践。处理切片是#54
它建议使用一种稍微复杂的模式来完全处理这个问题:拥有一个受保护的复制构造函数、一个受保护的纯虚拟DoClone和一个带有断言的公共克隆,该断言将告诉您(进一步)派生类是否未能正确实现DoClone。(克隆方法生成多态对象的正确深度副本。)
您还可以在基础显式上标记复制构造函数,如果需要,它允许显式切片。。。为什么丢失派生信息是不好的。。。因为派生类的作者可能已经更改了表示形式,因此切掉额外信息会更改对象表示的值。如果派生类用于缓存对某些操作更有效但转换bac代价昂贵的表示,则可能发生这种情况
B b;
A a = b;
B b1;
B b2;
A& a_ref = b2;
a_ref = b1;
//b2 now contains a mixture of b1 and b2!
class A {
public:
virtual A& operator= (const A& a) {
assign(a);
return *this;
}
protected:
void assign(const A& a) {
// copy members of A from a to this
}
};
class B : public A {
public:
virtual B& operator= (const A& a) {
if (const B* b = dynamic_cast<const B*>(&a))
assign(*b);
else
throw bad_assignment();
return *this;
}
protected:
void assign(const B& b) {
A::assign(b); // Let A's assign() copy members of A from b to this
// copy members of B from b to this
}
};
class baseclass
{
...
baseclass & operator =(const baseclass&);
baseclass(const baseclass&);
}
void function( )
{
baseclass obj1=m;
obj1=m;
}
#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'
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
}
#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'
void push_back(Action toAdd);
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
}