切片java_什么是对象切片? - javail的个人空间 - OSCHINA - 中文开源技术交流社区...

有人在IRC中提到它是切片问题。

#1楼

在我看来,除了您自己的类和程序的架构/设计不良时,切片并不是什么大问题。

如果我将子类对象作为参数传递给采用超类类型参数的方法,则我当然应该意识到这一点并在内部知道,所调用的方法将仅与超类(aka基类)对象一起使用。

在我看来,只有不合理的期望,即在请求基类的情况下提供子类会以某种方式导致特定于子类的结果,从而导致切片成为问题。 它要么使用该方法的设计不佳,要么使用子类的实现不佳。 我猜想这通常是出于权宜之计或性能提升而牺牲好的OOP设计的结果。

#2楼

好的,在阅读了很多解释对象切片的文章之后,我将尝试一下,但不会出现问题。

可能导致内存损坏的恶劣情况如下:

类在多态基类上提供(可能是编译器生成的)赋值。

客户端复制并切片派生类的实例。

客户端调用访问切片状态的虚拟成员函数。

#3楼

class A

{

int x;

};

class B

{

B( ) : x(1), c('a') { }

int x;

char c;

};

int main( )

{

A a;

B b;

a = b; // b.c == 'a' is "sliced" off

return 0;

}

#4楼

这里的大多数答案都无法解释切片的实际问题是什么。 他们只说明切片的良性案例,而不说明危险的切片。 像其他答案一样,假定您正在处理两个类A和B ,其中B (公开地)从A派生。

在这种情况下,C ++允许您将B的实例传递给A的赋值运算符(以及传递给副本构造函数)。 之所以可行,是因为B的实例可以转换为const A& ,这是赋值运算符和复制构造函数所期望的参数。

良性案例

B b;

A a = b;

那里什么都没发生-您要求A的实例,它是B的副本,而这正是您所得到的。 当然, a不会包含b的某些成员,但是应该如何? 毕竟是A ,而不是B ,所以它甚至都没有听说过这些成员,更不用说能够存储它们了。

奸诈案

B b1;

B b2;

A& a_ref = b2;

a_ref = b1;

//b2 now contains a mixture of b1 and b2!

您可能会认为b2将是b1的副本。 但是,可惜不是 ! 如果对其进行检查,您会发现b2是弗兰肯斯坦主义的生物,它由b1一些块( B继承自A的块)和b2一些块(仅B包含的块)组成。 哎哟!

发生了什么? 好吧,默认情况下,C ++不会将赋值运算符视为virtual 。 因此,行a_ref = b1将调用A的赋值运算符,而不是B的赋值运算符。 这是因为,对于非虚函数, 声明的类型(即A& )确定要调用哪个函数,而不是实际的类型(即B ,因为a_ref引用B的实例)。 现在, A的赋值运算符显然只知道A声明的成员,因此它将仅复制那些成员,而保持B添加的成员不变。

一个解法

通常只分配对象的一部分几乎没有什么意义,但是不幸的是,C ++没有提供内置的方式来禁止这种情况。 但是,您可以自己滚动。 第一步是使赋值运算符为virtual 。 这样可以确保始终调用的是实际类型的赋值运算符,而不是声明的类型的赋值运算符。 第二步是使用dynamic_cast验证分配的对象是否具有兼容的类型。 第三步是在(受保护的!)成员assign()进行实际分配,因为B的assign()可能要使用A的assign()复制A的成员。

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(&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的operator=协变量会覆盖返回类型,因为它知道它正在返回B的实例。

#5楼

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

说明:考虑以下类声明:

class baseclass

{

...

baseclass & operator =(const baseclass&);

baseclass(const baseclass&);

}

void function( )

{

baseclass obj1=m;

obj1=m;

}

由于基类复制函数对派生类一无所知,因此仅复制了派生类的基础部分。 这通常称为切片。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值