2

I am studying about when/why object slicing is dangerous.

I read a great link about what is safe slicing VS dangerous slicing.
Here is what I can summarize (roughly speaking):-

  • Safe when the base type is value (e.g. A).
  • Dangerous when the base type is reference (e.g. A&).

After read it, I created a test code in Visual Studio + Resharper (a VS plugin).
I think my case is safe. However, I got a warning at the marked line #1.

possibly unintended object slicing value-initialized from derived class 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 acts in a contradict way from my belief.

  • Warning when the type is value.
  • No warning when the type is reference (change #2 from B1 to B1&).
  • Always no warning when C derived from only B1, no matter #2 is. (B or B&)

It can by summarized into a table :-

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

However, here is what I expect :-

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

Inconsistency is mark with *.

Do I misunderstand about object slicing, or is Resharper wrong?

Community
  • 1
  • 1
javaLover
  • 6,347
  • 2
  • 22
  • 67
  • 5
    Actually slicing can only be a problem when assigning by value, if you use [pointers or references](https://stackoverflow.com/questions/15188894/why-doesnt-polymorphism-work-without-pointers-references) your objects will not slice and will correctly behave polymorphically. – Cory Kramer Mar 07 '17 at 13:05
  • (edited) Good point! You seem to be correct .... I understand it now. thank! – javaLover Mar 07 '17 at 13:08
  • @CoryKramer You can post as a solution if you wish. :) – javaLover Mar 07 '17 at 13:16

2 Answers2

1

No warning when the type is reference (change #2 from B1 to B1&).

When f is f(B1& b), then no slicing occurs. No warning is expected.

Always no warning when C derived from only B1, no matter #2 is. (B or B&)

When C is derived from only B1, its entire state is contained within the base subobject B1. Therefore no data is actually sliced off by the conversion. Perhaps your IDE considers that in such case the possibly unintentional conversion wouldn't be a problem.

Do I misunderstand about object slicing

You seem to assume that binding a base reference to an object would slice the base subobject. It does not. The "treacherous" (according to the linked answer) slicing occurs when the object is assigned to through the reference:

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 
}
eerorika
  • 232,697
  • 12
  • 197
  • 326
1

Resharper acts in a contradict way from my belief.

it acts in a correct way, lets see:

Warning when the type is value.

this is for this code:

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);
      }
};

in a function call, value initialization of variable b of type B1 from variable c of type C which is derived from B1, will execute a copy constructor of B1 whose signature is B1(const B1& rhs);, in this constructor (whether it is auto generated or not) only fields present in B1 will be copied from rhs, so the rest (part from B2 or C) will get sliced.

No warning when the type is reference (change #2 from B1 to B1&).

void f(B1& b){ } 

that is correct, this is how polymorphic objects should be passed around, by assigning objects to pointers or references of base class types.

Always no warning when C derived from only B1, no matter #2 is. (B or B&)

thats only because C has no fields, so there is no slicing in this case. Try adding int n; to C and warning will be shown again.

marcinj
  • 48,511
  • 9
  • 79
  • 100