E. Ginzburg
E. Ginzburg

Reputation: 253

how slicing of derived classes occurs?

I'm having trouble understanding how slicing occurs? for example, in this piece of code:

class A {
public:
  virtual h() {
    cout << "type A" << endl;
  }
};

class B : public A {
public:
  virtual h() override {
    cout << "type B" << endl;
  }
};

void f(A a) {
  a.h();
}

void g(A& a) {
  a.h();
}

int main() {
  A a1 = B(); // a1 is A and doesn't recognize any B properties
  A *a = new B();
  f(*a);
  g(*a);
}

I noticed that:

  1. variable a1 doens't know it's a B, but variable a does know. I refer this is happening because in variable a1 the assignment to B is by value, in contrst to variable a, where I create a pointer to B.

  2. same thing happens when I pass variable a to different functions - when I pass by value, it thinks it's an A, but when i pass by reference, it thinks it's B.

I would be happy if anyone could give me more extensive and deeper explanation. Thank you in advance!

Upvotes: 2

Views: 53

Answers (2)

eerorika
eerorika

Reputation: 238371

  1. variable a1 doens't know it's a B

More correctly: Variable a1 was declared to be an A, so it is an A. It is not a B, and never was a B. It's not about what the variable "knows"; it's about the type of the variable. a1 was initialised from a B by "slicing" a copy of the base sub object.

I would be happy if anyone could give me more extensive and deeper explanation.

Indirection is necessary for runtime polymorphism. An object of type A is always of type A and no other type. This is simply how types are in the language. One reason for this is that the compiler must know how much memory the object needs. If the compiler reserves memory for A, then how could a potentially bigger derived instance fit in the reserved memory?

But a pointer (or reference) to A can either point at a distinct A object, or it can point at a base sub object of a class that is derived from A. It doesn't matter how big the complete object is, a pointer can point at part of the object regardless, and this doesn't affect the size of the pointer itself.

how slicing of derived classes occurs?

Slicing occurs whenever you convert a derived object to a base type. The conversion copies the base class sub object. Note that when you convert a derived value to reference to base, no slicing occurs - unless you use that reference to initialise an object of the base type for instance.

Upvotes: 2

Vlad from Moscow
Vlad from Moscow

Reputation: 311038

In this statement

A a1 = B();

there is used the default copy constructor of the class A because the object a1 has the type A.

This constructor looks like

constexpr A( const A & );

So only subobject of the type A of the object of the class B is copied to the object a1. The table of pointers to virtual functions of the object a1 will contain pointer to its own virtual function.

In this declaration

A *a = new B();

the pointer a points to an object of the type B that contains the table of pointers to virtual functions that in turn contains a pointer to the virtual function of the class B.

So in this call

  g(*a);

the reference to the object of the dynamic type B is passed (the object itself was not changed when it was passed to the function by reference).

So within the function

void g(A& a) {
  a.h();
}.

there will be access to the table of virtual function pointers that contains a pointer to the virtual function of the class B. Here a new object of the class A is not created because the original object is passed by reference.

In this call

  f(*a);

the argument of the function is passed by value. That is there is a copy initialization of the parameter of the function declared like

void f(A a) {
  a.h();
}

So it is in fact the same case as in the declaration

A a1 = B();

considered above.

Upvotes: 1

Related Questions