1

I have been reading this answer which explained how slicing will modify only one part of an object. I'm wondering if the slicing behaviour explained in the treacherous case is guaranteed or undefined.

Given the following class structures (which I cannot modify):

class Combined : public Data, public Handler  
{  
    // no operator=() defined
    // implements abstract and/or virtual methods from Handler  
    // methods access members from Data  
};  

class Data  
{  
    // no operator=() defined
    // public members and public non-virtual methods only  
};  

class Handler  
{  
    // no operator=() defined
    // contains abstract as well as virtual methods  
    // protected/private members  
};

can I reliably use object slicing to assign only the Data portion of Combined, as such:

// Declaration
Data returnSomeDataFromSomewhere();

// real work starts here
Combined usable_obj;

Data& sliced_data = usable_obj;
sliced_data = returnSomeDataFromSomewhere();

usable_obj.actOnData();

or even

Combined usable_obj;
usable_obj.initialise();
usable_obj = returnSomeDataFromSomewhere();
usable_obj.actOnData();

An answer from this question suggests that explicitly calling Combined.Data::operator= (or is it Combined::Data::operator=?) achieves the same effect. It looks the same as assigning to the Data& object, but I'm confused by the caution about breaking the derived class' invariant.

If slicing happens to be undefined behaviour, I can always create a temporary Data object and copy each member individually since they are public, but I would prefer to not have to do that if there are 200 members in Data.

However, if the slicing behaviour is guaranteed, are there any pitfalls I should be aware of?


EDIT: Added restrictions on classes having no operator=.

Community
  • 1
  • 1
aerobot
  • 195
  • 1
  • 8
  • 1
    Do note that `Data& sliced_data = usable_obj;` does not slice. To slice you need `Data sliced_data = usable_obj;` – NathanOliver Nov 30 '16 at 14:03
  • @NathanOliver It also does not call any `operator=` at all. For which left hand side? It's a reference declaration cum mandatory initialization. But then I think the OP was referring to the line after that, and I'm less sure about what happens there. I guess it depends on whether the `operator=` is virtual. – Peter - Reinstate Monica Nov 30 '16 at 14:08
  • @PeterA.Schneider Since `returnSomeDataFromSomewhere()` returns a `Data` the assignment there is just going to change the data part of the `Combined` the reference refers to. – NathanOliver Nov 30 '16 at 14:13
  • 1
    @NathanOliver If `operator=` is virtual `Combined`'s implementation (which will be called because the lhs is a reference) can change anything it wants on the lhs (for example, set other members to default values). it may also just throw because the rhs's dynamic cast to `Combined` failed. – Peter - Reinstate Monica Nov 30 '16 at 14:14
  • @NathanOliver So I guess, in that answer, the base class reference is just being used to show how slicing can inadvertantly happen elsewhere? – aerobot Nov 30 '16 at 14:17
  • @PeterA.Schneider Pretty sure and [this](http://stackoverflow.com/questions/669818/virtual-assignment-operator-c) seems to back it up that even marked virtual the reference type `operator =` is only used. – NathanOliver Nov 30 '16 at 14:18
  • @PeterA.Schneider `operator=` is not virtual, nor even explicitly defined anywhere for all classes in question. I'll edit the question to clarify that. – aerobot Nov 30 '16 at 14:19
  • @aerobot It depends on whether `operator=` is virtual or not. If not (for example, because the default is used), `Data`'s assignment operator will be called which will only change `Data`'s members. – Peter - Reinstate Monica Nov 30 '16 at 14:19
  • @PeterA.Schneider `Data's assignment operator will be called which will only change Data's members` So this assignment behaviour is well-defined and (more importantly) safe in the context of a multiple-inheritance class? – aerobot Nov 30 '16 at 14:25
  • Another comment: `sliced_data = returnSomeDataFromSomewhere();` is actually *the opposite of slicing!* The definition of slicing is: you have the base class object on the lhs and the derived on the rhs, and you take only the base part of the derived and assign it to the lhs. Here, by contrast, you have the derived on the lhs and take *all* of the base on the rhs... – Peter - Reinstate Monica Nov 30 '16 at 14:29

1 Answers1

1

I'll jump.

First of all, this is not slicing, as explained in a comment.

This is simply calling a function defined in the base class. It is one of the functions which are special, but not that special (no magic involved). The default implementation is to copy the members of the object on the right hand side (which is operator='s argument) to the corresponding members of the object the member function is called for, which is the left hand side. As far as I can see this should be safe language-wise. (It may of course be that this partial change of the caller is logically problematic because it violates invariants of Combined.)

Peter - Reinstate Monica
  • 15,048
  • 4
  • 37
  • 62
  • I'm much enlightened. Having a different perspective, backed up by insight, is an amazing thing =) I'll leave this open for maybe a day or two more, but it looks like you're getting the tick. – aerobot Nov 30 '16 at 15:07