2017-03-07 24 views
2

我正在研究什么时候/为什么对象切片是危险的。对象切片:pass通过值导出为基础 - 安全还是危险?

我读了一个关于what is safe slicing VS dangerous slicing的好链接。
这里是我可以总结一下(粗略地说): -

  • 安全当基类型是(例如A)。
  • 危险当基础类型是参考(例如A&)。

读之后,我在Visual Studio中 + ReSharper的(一个VS插件)创建的测试代码。
我觉得我的情况是安全。但是,我在标记线#1处收到警告。

衍生自C类可能无意对象切片值初始化

class B1{ int field1=0; }; 
class B2{ int field2=0; }; 
class C: public B1,public B2{ }; 
class Test{ 
    void f(B1 b){ }        #2 
    void f2(){ 
     C c; 
     f(c); 
     //^ possibly unintended object slicing #1 
    } 
}; 

ReSharper的行为在从我相信一个矛盾的方式。

  • 警告当类型为
  • 无警告当类型是参考(更改#2从B1B1&)。
  • 总是没有警告C只从B1派生,无论#2是。 (BB&

它可以被归纳为一个表: -

     | #2=B1 | #2=B1& 
================================================== 
multi-inherit   | warn* | no-warn*  
-------------------------------------------------- 
inherit only from B1 | no-warn | no-warn  

然而,这里是我想到: -

     | #2=B1 | #2=B1& 
=================================================================== 
multi-inherit   |  safe* | dangerous*  
------------------------------------------------------------------- 
inherit only from B1 |  safe |  safe  

不一致刻度*

难道我误解了对象切片,或者是Resharper错?

+5

实际上,如果使用[指针或引用]指定值时,切片只能是一个问题(https://stackoverflow.com/questions/15188894/why-doesnt-polymorphism-work-without-pointers-references)你的对象不会切片,并且会正确地表现为多态。 – CoryKramer

+0

(编辑)好点!你似乎是对的......我现在明白了。谢谢! – javaLover

+0

@CoryKramer如果您愿意,您可以发布解决方案。 :) – javaLover

回答

1

ReSharper的行为。

它以正确的方式起作用,让我们看看:

警告当类型为值。

这是此代码:

class B1{ int field1=0; }; 
class B2{ int field2=0; }; 
class C: public B1,public B2{ }; 
class Test{ 
    void f(B1 b){ } 
    void f2(){ 
     C c; 
     f(c); 
     } 
}; 
在函数调用

,从C类型的可变c这是从B1衍生B1类型的可变b的值初始化,将执行的一个拷贝构造B1的签名是B1(const B1& rhs);,在这个构造函数中(不管它是否是自动生成的)只有B1中的字段将被复制rhs,所以其余部分(B2C)将被切片。

当类型是参考时(从B1更改为B),不会有任何警告。

void f(B1& b){ } 

这是正确的,这是对象如何多态应通过周围,通过分配对象的指针或基类类型的引用。

当C从B1派生出来时,无论#2是什么,总是没有警告。 (B或B &)仅

那是因为C没有字段,所以在这种情况下,没有切片。尝试将int n;添加到C,并再次显示警告。

+0

'尝试添加int n;到C' < - 奇怪的是,这种说法启发我。它赢得了我的心。 – javaLover

1

当类型为参考时(从B1更改为B1至B1 &),不会有任何警告。

当f是f(B1& b)时,则不发生切片。预计不会有任何警告。

当C从B1派生出来时,无论#2是什么,总是没有警告。 (B或B &)

当C仅从B1派生时,其整个状态包含在基础子对象B1内。因此,没有数据实际上被转换切掉。也许您的IDE认为在这种情况下,可能无意的转换不会成为问题。

难道我误解了有关对象切片

您似乎认为基本参考绑定到一个对象将切片的基子对象。它不是。所述“诡谲”(根据连接的回答)切片时出现对象通过参考分配给:在从我相信一个矛盾方式

void f(B1& b){ 
    b = C{}; // the B2 portion of the argument is sliced off; 
      // only B1 portion is assigned. If b refers to a 
      // C, then ((C&)b)::B2 remains unmodified. 
      // If that was unintentional, then you were affected 
      // by the treacherousness 
}