object slicing

R

Rahul

Hi Everyone,

I was working around object slicing (pass by value) and was
wondering how it is specified in the standard,

class A
{
};

class B: public A
{
};

void fun(A obj)
{
}

int main()
{
B obj;
fun(obj); // obj is sliced into type of A, but how
exactly does it happen?
}

I noticed that the copy constructor of A is invoked and "thinking in c+
+" claims that to be essential for updating the vptr (if present) with
the proper VTABLE. [this is not in the above case]

Thanks in advance!!!
 
V

Victor Bazarov

Rahul said:
I was working around object slicing (pass by value) and was
wondering how it is specified in the standard,

It's not, really. The standard says that the object of the
derived type is converted into an object of the base type,
but does not say how the code does that. To specify it would
be to impose undue limitations on what the compiler can do.

In your case, however, it's a temporary of type 'A' that is
created. The creation of the temporary is done by copy-
constructing.
class A
{
};

class B: public A
{
};

void fun(A obj)
{
}

int main()
{
B obj;
fun(obj); // obj is sliced into type of A, but how
exactly does it happen?

The compiler constructs a temporary of type 'A' from the 'A' part
of the 'obj' (using the appropriate copy constructor). Any 'B'
obejct contains the 'A' part, and then some other stuff that makes
it different from an 'A' object. The other stuff is ignored during
copying.
}

I noticed that the copy constructor of A is invoked and "thinking in
c+ +" claims that to be essential for updating the vptr (if present)
with the proper VTABLE. [this is not in the above case]

The copy constructor invocation is essential for the process. But
the vtbl is not the reason. The object created by the slicing
process has to be changeable (inside your 'fun' function), and
should not cause any changes in the originating 'obj'. That's
why a different object (a temporary) is constructed.

V
 
J

James Kanze

It's not, really. The standard says that the object of the
derived type is converted into an object of the base type,
but does not say how the code does that. To specify it would
be to impose undue limitations on what the compiler can do.

Well, the standard does say a little bit more. For example, any
time an object is created, a constructor is called. And
overload resolution is applied as usual.
In your case, however, it's a temporary of type 'A' that is
created. The creation of the temporary is done by copy-
constructing.

That's the usual case.

If A had a constructor A::A( B const& ), in addition to the copy
constructor, then this constructor would be used, instead of the
copy constructor. Similarly, if B had a user defined conversion
to A, that would be used. (I think---but the rules here are
very subtle.)

As far as the standard is concerned, there is no such thing as
"slicing". You're passing an object of type B, and you need an
object of type A. The compiler does the usual overload
resolution things to find the appropriate was to do the
conversion.

In practice, of course, most of the time, the base class will
have a copy constructor, which will take a reference to base.
Which means that if no better conversion is available, it will
be used. When this happens accidentally, it is called slicing.
The compiler constructs a temporary of type 'A' from the 'A' part
of the 'obj' (using the appropriate copy constructor).

In practice. Note however that the copy constructor of A could
call virtual functions on the object being copied, which would
result in the derived type being taken into account. (Of
course, the compiler generated copy constructor doesn't do this,
and I can't say off hand that I've seen any user defined copy
constructors which do it either. But it is possible.)
Any 'B' obejct contains the 'A' part, and then some other
stuff that makes it different from an 'A' object. The other
stuff is ignored during copying.

By the compiler generated copy constructor.
}
I noticed that the copy constructor of A is invoked and
"thinking in c++" claims that to be essential for updating
the vptr (if present) with the proper VTABLE. [this is not
in the above case]
The copy constructor invocation is essential for the process.
But the vtbl is not the reason.

Not the only reason. The vptr *is* one reason why a constructor
is *always* called when creating an object.
The object created by the slicing process has to be changeable
(inside your 'fun' function), and should not cause any changes
in the originating 'obj'. That's why a different object (a
temporary) is constructed.

In my experience, inheritance doesn't work well with assignment
and copy; if a class is designed to be used as a base class,
most of the time, you should block copy and assignment (or force
copy to go through a virtual function, such as clone). And if a
class isn't designed to be used as a base class, it's generally
an error to derived from it. The result is that if you've done
any design up front, and you're religious about blocking copy
and assignment when they're not wanted, slicing isn't a problem.

Also, of course, it's fairly rare to derive from a concrete
class. And if the base class is abstract, you can't slice to
it, since no instances of it can exist.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,119
Latest member
IrmaNorcro
Top