class A {
int foo;
};
class B : public A {
int bar;
};
因此类型 b 的对象具有两个数据成员, foo 和 bar 。
然后,如果要编写这篇文章:
B b;
A a = b;
那么 b 中的信息 bar 在 a 中丢失。
"Slicing" is where you assign an object of a derived class to an instance of a base class, thereby losing part of the information - some of it is "sliced" away.
For example,
class A {
int foo;
};
class B : public A {
int bar;
};
So an object of type B has two data members, foo and bar.
Then if you were to write this:
B b;
A a = b;
Then the information in b about member bar is lost in a.
这里的大多数答案无法解释切片的实际问题。他们只解释了切片的良性案例,而不是危险的案例。假设像其他答案一样,您正在处理两个类 a 和 b ,其中 b 从公开派生(公开) 。
在这种情况下,C ++使您可以将 b 的实例传递给 a 的分配操作员(以及复制构造函数)。之所以起作用,是因为 b 的实例可以转换为 const a& ,这是分配运算符和复制构建者期望其参数的原因。
良性案例
B b;
A a = b;
在那里没有任何不好的事 - 您要求 a 的实例,该实例是 b 的副本,这正是您所获得的。当然, a 不包含 b 的某些成员,但是该如何?毕竟,这是一个 a ,不是 b ,因此它甚至没有关于这些成员的听到的,更不用说能够存储他们。
您可能会认为 b2 的危险情况
B b1;
B b2;
A& a_ref = b2;
a_ref = b1;
//b2 now contains a mixture of b1 and b2!
将是 b1 之后的副本。但是,a,不是!如果检查它,您会发现 b2 是弗兰肯斯坦的生物 a ),以及 b2 的一些块(仅包含 b 的块)。哎哟!
发生了什么?好吧,默认情况下,C ++不会将分配运算符视为 Virtual 。因此,行 a_ref = b1 将调用 a 的分配操作员,而不是 b 的分配操作员。这是因为,对于非虚拟函数,声明为(形式: static )类型( a& )确定哪个函数称为,与实际(形式上: dynamic )类型相反(这将是 b ,因为 a_ref 引用引用实例 b )。现在, a 的分配操作员显然只知道 a 中声明的成员,因此它将仅复制这些成员,而将成员添加到 b 不变。
解决方案
仅分配给对象部分的 通常毫无意义,但是不幸的是,C ++没有内置的方式禁止此方法。但是,您可以自己滚动。第一步是使分配运算符 virtual 。这将保证始终是实际类型的分配操作员,而不是声明的类型。第二步是使用 dynamic_cast 来验证分配的对象是否具有兼容类型。第三步是在(受保护的!)成员 agiss()中进行实际分配,因为 b 's nistion> nistion()可能会想要使用 a 's nistion()复制 a 's,成员。
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
}
};
请注意,为了纯粹的方便, b 's operator = 协变量覆盖返回类型,因为它知道它正在返回一个 b 。
Most answers here fail to explain what the actual problem with slicing is. They only explain the benign cases of slicing, not the treacherous ones. Assume, like the other answers, that you're dealing with two classes A and B, where B derives (publicly) from A.
In this situation, C++ lets you pass an instance of B to A's assignment operator (and also to the copy constructor). This works because an instance of B can be converted to a const A&, which is what assignment operators and copy-constructors expect their arguments to be.
The benign case
B b;
A a = b;
Nothing bad happens there - you asked for an instance of A which is a copy of B, and that's exactly what you get. Sure, a won't contain some of b's members, but how should it? It's an A, after all, not a B, so it hasn't even heard about these members, let alone would be able to store them.
The treacherous case
B b1;
B b2;
A& a_ref = b2;
a_ref = b1;
//b2 now contains a mixture of b1 and b2!
You might think that b2 will be a copy of b1 afterward. But, alas, it's not! If you inspect it, you'll discover that b2 is a Frankensteinian creature, made from some chunks of b1 (the chunks that B inherits from A), and some chunks of b2 (the chunks that only B contains). Ouch!
What happened? Well, C++ by default doesn't treat assignment operators as virtual. Thus, the line a_ref = b1 will call the assignment operator of A, not that of B. This is because, for non-virtual functions, the declared (formally: static) type (which is A&) determines which function is called, as opposed to the actual (formally: dynamic) type (which would be B, since a_ref references an instance of B). Now, A's assignment operator obviously knows only about the members declared in A, so it will copy only those, leaving the members added in B unchanged.
A solution
Assigning only to parts of an object usually makes little sense, yet C++, unfortunately, provides no built-in way to forbid this. You can, however, roll your own. The first step is making the assignment operator virtual. This will guarantee that it's always the actual type's assignment operator which is called, not the declared type's. The second step is to use dynamic_cast to verify that the assigned object has a compatible type. The third step is to do the actual assignment in a (protected!) member assign(), since B's assign() will probably want to use A's assign() to copy A's, members.
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
}
};
Note that, for pure convenience, B's operator= covariantly overrides the return type, since it knows that it's returning an instance of B.
If You have a base class A and a derived class B, then You can do the following.
void wantAnA(A myA)
{
// work with myA
}
B derived;
// work with the object "derived"
wantAnA(derived);
Now the method wantAnA needs a copy of derived. However, the object derived cannot be copied completely, as the class B could invent additional member variables which are not in its base class A.
Therefore, to call wantAnA, the compiler will "slice off" all additional members of the derived class. The result might be an object you did not want to create, because
it may be incomplete,
it behaves like an A-object (all special behaviour of the class B is lost).
So it's when you assign an object of a subclass to the super class. The superclass knows nothing of the additional information in the subclass, and hasn't got room to store it, so the additional information gets "sliced off".
If those links don't give enough info for a "good answer" please edit your question to let us know what more you're looking for.
The slicing problem is serious because it can result in memory corruption, and it is very difficult to guarantee a program does not suffer from it. To design it out of the language, classes that support inheritance should be accessible by reference only (not by value). The D programming language has this property.
Consider class A, and class B derived from A. Memory corruption can happen if the A part has a pointer p, and a B instance that points p to B's additional data. Then, when the additional data gets sliced off, p is pointing to garbage.
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???
}
I see all the answers mention when object slicing happens when data members are sliced. Here I give an example that the methods are not overridden:
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 (object b) is derived from A (object a1 and a2). b and a1, as we expect, call their member function. But from polymorphism viewpoint we don’t expect a2, which is assigned by b, to not be overridden. Basically, a2 only saves A-class part of b and that is object slicing in C++.
To solve this problem, a reference or pointer should be used
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
}
对象切片发生在将派生的类对象分配给基类对象时,将派生的类对象的其他属性切成薄片以形成基类对象。
In C++, a derived class object can be assigned to a base class object, but the other way is not possible.
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
}
Object slicing happens when a derived class object is assigned to a base class object, additional attributes of a derived class object are sliced off to form the base class object.
So ... Why is losing the derived information bad? ... because the author of the derived class may have changed the representation such that slicing off the extra information changes the value being represented by the object. This can happen if the derived class if used to cache a representation that is more efficient for certain operations, but expensive to transform back to the base representation.
Also thought someone should also mention what you should do to avoid slicing...
Get a copy of C++ Coding Standards, 101 rules guidlines, and best practices. Dealing with slicing is #54.
It suggests a somewhat sophisticated pattern to fully deal with the issue: have a protected copy constructor, a protected pure virtual DoClone, and a public Clone with an assert which will tell you if a (further) derived class failed to implement DoClone correctly. (The Clone method makes a proper deep copy of the polymorphic object.)
You can also mark the copy constructor on the base explicit which allows for explicit slicing if it is desired.
C ++中的切片问题来自其对象的值语义,这主要是由于与C结构的兼容性。您需要使用显式参考或指针语法来实现在大多数其他使用对象的语言中发现的“正常”对象行为,即始终通过参考传递对象。
简短的答案是,通过将派生对象分配给基本对象 by Value ,即剩下的对象只是派生对象的一部分。为了保留价值语义,切片是一种合理的行为,并且具有相对罕见的用途,在大多数其他语言中都不存在。有些人认为这是C ++的特征,而许多人认为它是C ++的怪癖/错误之一。
The slicing problem in C++ arises from the value semantics of its objects, which remained mostly due to compatibility with C structs. You need to use explicit reference or pointer syntax to achieve "normal" object behavior found in most other languages that do objects, i.e., objects are always passed around by reference.
The short answers is that you slice the object by assigning a derived object to a base object by value, i.e. the remaining object is only a part of the derived object. In order to preserve value semantics, slicing is a reasonable behavior and has its relatively rare uses, which doesn't exist in most other languages. Some people consider it a feature of C++, while many considered it one of the quirks/misfeatures of C++.
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(后代类对象)指向。另外,如果您需要使用函数,则该功能必须是虚拟函数。
1. THE DEFINITION OF SLICING PROBLEM
If D is a derived class of the base class B, then you can assign an object of type Derived to a variable (or parameter) of type Base.
EXAMPLE
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
Although the above assignment is allowed, the value that is assigned to the variable pet loses its breed field. This is called the slicing problem.
2. HOW TO FIX THE SLICING PROBLEM
To defeat the problem, we use pointers to dynamic variables.
EXAMPLE
Pet *ptrP;
Dog *ptrD;
ptrD = new Dog;
ptrD->name = "Tommy";
ptrD->breed = "Kangal Dog";
ptrP = ptrD;
cout << ((Dog *)ptrP)->breed;
In this case, none of the data members or member functions of the dynamic variable
being pointed to by ptrD (descendant class object) will be lost. In addition, if you need to use functions, the function must be a virtual function.
It seems to me, that slicing isn't so much a problem other than when your own classes and program are poorly architected/designed.
If I pass a subclass object in as a parameter to a method, which takes a parameter of type superclass, I should certainly be aware of that and know the internally, the called method will be working with the superclass (aka baseclass) object only.
It seems to me only the unreasonable expectation that providing a subclass where a baseclass is requested, would somehow result in subclass specific results, would cause slicing to be a problem. Its either poor design in the use of the method or a poor subclass implementation. I'm guessing its usually the result of sacrificing good OOP design in favor of expediency or performance gains.
Slicing means that the data added by a subclass are discarded when an object of the subclass is passed or returned by value or from a function expecting a base class object.
Explanation:
Consider the following class declaration:
As baseclass copy functions don't know anything about the derived only the base part of the derived is copied. This is commonly referred to as slicing.
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
}
when a derived class object is assigned to a base class object, additional attributes of a derived class object are sliced off (discard) form the base class object.
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'
When a Derived class Object is assigned to Base class Object, all the members of derived class object is copied to base class object except the members which are not present in the base class. These members are Sliced away by the compiler.
This is called Object Slicing.
Here is an Example:
#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;
}
It will generate:
[Error] 'class Base' has no member named 'd'
[Error] 'class Base' has no member named 'e'
发布评论
评论(17)
“切片”是您将派生类的对象分配给基类实例的地方,从而丢失了一部分信息 - 其中一些是“切成”的。
例如,
因此类型
b
的对象具有两个数据成员,foo
和bar
。然后,如果要编写这篇文章:
那么
b
中的信息 bar 在a
中丢失。"Slicing" is where you assign an object of a derived class to an instance of a base class, thereby losing part of the information - some of it is "sliced" away.
For example,
So an object of type
B
has two data members,foo
andbar
.Then if you were to write this:
Then the information in
b
about memberbar
is lost ina
.这里的大多数答案无法解释切片的实际问题。他们只解释了切片的良性案例,而不是危险的案例。假设像其他答案一样,您正在处理两个类
a
和b
,其中b
从公开派生(公开)
。在这种情况下,C ++使您可以将
b
的实例传递给a
的分配操作员(以及复制构造函数)。之所以起作用,是因为b
的实例可以转换为const a&amp;
,这是分配运算符和复制构建者期望其参数的原因。良性案例
在那里没有任何不好的事 - 您要求
a
的实例,该实例是b
的副本,这正是您所获得的。当然,a
不包含b
的某些成员,但是该如何?毕竟,这是一个a
,不是b
,因此它甚至没有关于这些成员的听到的,更不用说能够存储他们。您可能会认为
b2
的危险情况将是
b1
之后的副本。但是,a,不是!如果检查它,您会发现b2
是弗兰肯斯坦的生物a
),以及b2
的一些块(仅包含b
的块)。哎哟!发生了什么?好吧,默认情况下,C ++不会将分配运算符视为
Virtual
。因此,行a_ref = b1
将调用a
的分配操作员,而不是b
的分配操作员。这是因为,对于非虚拟函数,声明为(形式: static )类型(a&amp;
)确定哪个函数称为,与实际(形式上: dynamic )类型相反(这将是b
,因为a_ref
引用引用实例b
)。现在,a
的分配操作员显然只知道a
中声明的成员,因此它将仅复制这些成员,而将成员添加到b 不变。
解决方案
仅分配给对象部分的 通常毫无意义,但是不幸的是,C ++没有内置的方式禁止此方法。但是,您可以自己滚动。第一步是使分配运算符 virtual 。这将保证始终是实际类型的分配操作员,而不是声明的类型。第二步是使用
dynamic_cast
来验证分配的对象是否具有兼容类型。第三步是在(受保护的!)成员agiss()
中进行实际分配,因为b
'snistion> nistion()
可能会想要使用a
'snistion()
复制a
's,成员。请注意,为了纯粹的方便,
b
'soperator =
协变量覆盖返回类型,因为它知道它正在返回一个b 。
Most answers here fail to explain what the actual problem with slicing is. They only explain the benign cases of slicing, not the treacherous ones. Assume, like the other answers, that you're dealing with two classes
A
andB
, whereB
derives (publicly) fromA
.In this situation, C++ lets you pass an instance of
B
toA
's assignment operator (and also to the copy constructor). This works because an instance ofB
can be converted to aconst A&
, which is what assignment operators and copy-constructors expect their arguments to be.The benign case
Nothing bad happens there - you asked for an instance of
A
which is a copy ofB
, and that's exactly what you get. Sure,a
won't contain some ofb
's members, but how should it? It's anA
, after all, not aB
, so it hasn't even heard about these members, let alone would be able to store them.The treacherous case
You might think that
b2
will be a copy ofb1
afterward. But, alas, it's not! If you inspect it, you'll discover thatb2
is a Frankensteinian creature, made from some chunks ofb1
(the chunks thatB
inherits fromA
), and some chunks ofb2
(the chunks that onlyB
contains). Ouch!What happened? Well, C++ by default doesn't treat assignment operators as
virtual
. Thus, the linea_ref = b1
will call the assignment operator ofA
, not that ofB
. This is because, for non-virtual functions, the declared (formally: static) type (which isA&
) determines which function is called, as opposed to the actual (formally: dynamic) type (which would beB
, sincea_ref
references an instance ofB
). Now,A
's assignment operator obviously knows only about the members declared inA
, so it will copy only those, leaving the members added inB
unchanged.A solution
Assigning only to parts of an object usually makes little sense, yet C++, unfortunately, provides no built-in way to forbid this. You can, however, roll your own. The first step is making the assignment operator virtual. This will guarantee that it's always the actual type's assignment operator which is called, not the declared type's. The second step is to use
dynamic_cast
to verify that the assigned object has a compatible type. The third step is to do the actual assignment in a (protected!) memberassign()
, sinceB
'sassign()
will probably want to useA
'sassign()
to copyA
's, members.Note that, for pure convenience,
B
'soperator=
covariantly overrides the return type, since it knows that it's returning an instance ofB
.如果您有一个基类
a
和派生的类b
,则可以执行以下操作。现在,方法
wantana
需要派生
的副本。但是,由于类b
可以发明不在其基类a
的其他成员变量,因此无法完全复制对象派生
。因此,要调用
Wantana
,编译器将“切片”派生类的所有其他成员。结果可能是您不想创建的对象,因为a
-Object(类b
的所有特殊行为都是)。If You have a base class
A
and a derived classB
, then You can do the following.Now the method
wantAnA
needs a copy ofderived
. However, the objectderived
cannot be copied completely, as the classB
could invent additional member variables which are not in its base classA
.Therefore, to call
wantAnA
, the compiler will "slice off" all additional members of the derived class. The result might be an object you did not want to create, becauseA
-object (all special behaviour of the classB
is lost).这些都是很好的答案。我只想添加一个执行示例,当时通过值vs通过参考:
输出为:
These are all good answers. I would just like to add an execution example when passing objects by value vs by reference:
The output is:
Google在Google的“ C ++切片”中的第三场比赛为我提供了这篇Wikipedia文章和此(加热,但前几个帖子定义了问题):
http://bytes.com/forum/thread163565.html 超级阶级的子类。超级类别不了解子类中的其他信息,也没有存储空间,因此附加信息将“切片”。
如果这些链接没有提供足够的信息以提供“好答案”,请编辑您的问题,让我们知道您要寻找什么。
Third match in google for "C++ slicing" gives me this Wikipedia article http://en.wikipedia.org/wiki/Object_slicing and this (heated, but the first few posts define the problem) : http://bytes.com/forum/thread163565.html
So it's when you assign an object of a subclass to the super class. The superclass knows nothing of the additional information in the subclass, and hasn't got room to store it, so the additional information gets "sliced off".
If those links don't give enough info for a "good answer" please edit your question to let us know what more you're looking for.
切片问题是严重的,因为它可能导致记忆损坏,而且很难保证程序不会遭受损害。为了通过语言进行设计,仅应通过参考(而不是通过值)访问支持继承的类。 D编程语言具有此属性。
如果A零件具有指针P,并且将P指向B的附加数据时,请考虑A类和B类A类。内存损坏可能会发生。然后,当其他数据切成薄片时,P指向垃圾。
The slicing problem is serious because it can result in memory corruption, and it is very difficult to guarantee a program does not suffer from it. To design it out of the language, classes that support inheritance should be accessible by reference only (not by value). The D programming language has this property.
Consider class A, and class B derived from A. Memory corruption can happen if the A part has a pointer p, and a B instance that points p to B's additional data. Then, when the additional data gets sliced off, p is pointing to garbage.
当数据成员切成薄片时发生对象切片时,我会看到所有答案。在这里,我举了一个示例,即这些方法没有被覆盖:
B(对象B)源自A(对象A1和A2)。正如我们期望的那样,B和A1称其会员功能。但是从多态性的角度来看,我们不希望B分配的A2不会被覆盖。基本上,A2仅保存B的A级部分,即在C ++中切片。
要解决此问题,应使用参考或指针
或
I see all the answers mention when object slicing happens when data members are sliced. Here I give an example that the methods are not overridden:
B (object b) is derived from A (object a1 and a2). b and a1, as we expect, call their member function. But from polymorphism viewpoint we don’t expect a2, which is assigned by b, to not be overridden. Basically, a2 only saves A-class part of b and that is object slicing in C++.
To solve this problem, a reference or pointer should be used
or
在C ++中,可以将派生的类对象分配给基类对象,但不可能。
对象切片发生在将派生的类对象分配给基类对象时,将派生的类对象的其他属性切成薄片以形成基类对象。
In C++, a derived class object can be assigned to a base class object, but the other way is not possible.
Object slicing happens when a derived class object is assigned to a base class object, additional attributes of a derived class object are sliced off to form the base class object.
那么...为什么失去派生信息不好? ...因为派生类的作者可能改变了表示形式,从而切除额外信息会更改对象所代表的值。如果派生类(如果用于缓存)表示某些操作更有效但转换回基本表示效率更高的表示,则可能发生这种情况。
还认为某人还应该提及您应该做什么以避免切片...
获取C ++编码标准,101规则指南和最佳实践的副本。处理切片是#54。
它提出了一种有些复杂的模式来充分处理这个问题:拥有一个受保护的复制构造函数,受保护的纯虚拟doclone和一个带有断言的公共克隆,它将告诉您(进一步的)派生类是否无法正确实现doclone。 (克隆方法使多态对象的适当深副本进行了适当的深层副本。)
您还可以在基本的显式上标记复制构造函数,如果需要,可以明确切片。
So ... Why is losing the derived information bad? ... because the author of the derived class may have changed the representation such that slicing off the extra information changes the value being represented by the object. This can happen if the derived class if used to cache a representation that is more efficient for certain operations, but expensive to transform back to the base representation.
Also thought someone should also mention what you should do to avoid slicing...
Get a copy of C++ Coding Standards, 101 rules guidlines, and best practices. Dealing with slicing is #54.
It suggests a somewhat sophisticated pattern to fully deal with the issue: have a protected copy constructor, a protected pure virtual DoClone, and a public Clone with an assert which will tell you if a (further) derived class failed to implement DoClone correctly. (The Clone method makes a proper deep copy of the polymorphic object.)
You can also mark the copy constructor on the base explicit which allows for explicit slicing if it is desired.
C ++中的切片问题来自其对象的值语义,这主要是由于与C结构的兼容性。您需要使用显式参考或指针语法来实现在大多数其他使用对象的语言中发现的“正常”对象行为,即始终通过参考传递对象。
简短的答案是,通过将派生对象分配给基本对象 by Value ,即剩下的对象只是派生对象的一部分。为了保留价值语义,切片是一种合理的行为,并且具有相对罕见的用途,在大多数其他语言中都不存在。有些人认为这是C ++的特征,而许多人认为它是C ++的怪癖/错误之一。
The slicing problem in C++ arises from the value semantics of its objects, which remained mostly due to compatibility with C structs. You need to use explicit reference or pointer syntax to achieve "normal" object behavior found in most other languages that do objects, i.e., objects are always passed around by reference.
The short answers is that you slice the object by assigning a derived object to a base object by value, i.e. the remaining object is only a part of the derived object. In order to preserve value semantics, slicing is a reasonable behavior and has its relatively rare uses, which doesn't exist in most other languages. Some people consider it a feature of C++, while many considered it one of the quirks/misfeatures of C++.
1。切片问题的定义
如果d是基类B的派生类,则可以将派生的类型对象分配给类型碱的变量(或参数)。
示例
尽管允许上述分配,但分配给可变宠物的值却失去了其繁殖场。这称为切片问题。
2。如何解决切片问题
以打败问题,我们将指针用于动态变量。
下
在这种情况
被PTRD(后代类对象)指向。另外,如果您需要使用函数,则该功能必须是虚拟函数。
1. THE DEFINITION OF SLICING PROBLEM
If D is a derived class of the base class B, then you can assign an object of type Derived to a variable (or parameter) of type Base.
EXAMPLE
Although the above assignment is allowed, the value that is assigned to the variable pet loses its breed field. This is called the slicing problem.
2. HOW TO FIX THE SLICING PROBLEM
To defeat the problem, we use pointers to dynamic variables.
EXAMPLE
In this case, none of the data members or member functions of the dynamic variable
being pointed to by ptrD (descendant class object) will be lost. In addition, if you need to use functions, the function must be a virtual function.
在我看来,切片并不是您自己的课程和程序构建/设计不佳的问题。
如果我将一个子类作为参数传递给一个方法,该方法采用类型超级类的参数,我当然应该意识到这一点,并且内部知道该方法,该方法将仅与超级类(aka Baseclass)对象一起使用。
在我看来,只有一个不合理的期望,即提供要求基本的子类,以某种方式产生子类特定结果,这会导致切片是一个问题。它在使用该方法方面的设计差,或者子类实施不良。我猜这通常是牺牲良好的OOP设计以支持权宜或性能提高的结果。
It seems to me, that slicing isn't so much a problem other than when your own classes and program are poorly architected/designed.
If I pass a subclass object in as a parameter to a method, which takes a parameter of type superclass, I should certainly be aware of that and know the internally, the called method will be working with the superclass (aka baseclass) object only.
It seems to me only the unreasonable expectation that providing a subclass where a baseclass is requested, would somehow result in subclass specific results, would cause slicing to be a problem. Its either poor design in the use of the method or a poor subclass implementation. I'm guessing its usually the result of sacrificing good OOP design in favor of expediency or performance gains.
好的,阅读了许多帖子解释对象切片的文章后,我会尝试一下,但不是如何成为问题。
可能导致内存损坏的恶性场景如下:
OK, I'll give it a try after reading many posts explaining object slicing but not how it becomes problematic.
The vicious scenario that can result in memory corruption is the following:
切片意味着,当子类的对象通过值或从期望基类对象的函数传递或返回时,子类添加的数据将被丢弃。
解释:
考虑以下类声明:
由于基本副本函数对派生的衍生所不了解,仅复制了派生的基本部分。这通常称为切片。
Slicing means that the data added by a subclass are discarded when an object of the subclass is passed or returned by value or from a function expecting a base class object.
Explanation:
Consider the following class declaration:
As baseclass copy functions don't know anything about the derived only the base part of the derived is copied. This is commonly referred to as slicing.
当将派生的类对象分配给基类对象时,将派生类对象的其他属性切开(丢弃)形成基类对象。
when a derived class object is assigned to a base class object, additional attributes of a derived class object are sliced off (discard) form the base class object.
当将派生的类对象分配给基类对象时,除了基类中不存在的成员之外,将派生的类对象的所有成员复制到base类对象。这些成员被编译器切开。
这称为对象切片。
这是一个示例:
它将生成:
When a Derived class Object is assigned to Base class Object, all the members of derived class object is copied to base class object except the members which are not present in the base class. These members are Sliced away by the compiler.
This is called Object Slicing.
Here is an Example:
It will generate: