1

Here's an instantition: Base * ptr = new Derived() ;

After working with ptr, I want to reset it.

Why derived class members are not reset when doing *ptr = Derived() ; while base class members are ?

See for yourself in a complete example:

#include <iostream>
#include <vector>

void print_array(const std::vector<int> & vec, const std::string & name = "" )
{
    std::cout << name << " => [ " ;
    for (unsigned i = 0; i < vec.size(); ++i)
    {
        std::cout << vec[i] << " " ;
    }
    std::cout << "]" << std::endl ;
}

void do_stuff(std::vector<int> & vec, unsigned size)
{
    vec.resize(size) ;
    std::fill(vec.begin(), vec.end(), size) ;
}

class Base
{
public:
    std::vector<int> base ;

    Base() {}
    virtual ~Base() {}
};

class Derived : public Base
{
public:
    std::vector<int> derv ;

    Derived() {}
    virtual ~Derived() {}
};


int main()
{
    // Working but without polymorphism
    // Derived * ptr = new Derived() ;

    //Non-working
    Base * ptr = new Derived() ;

    std::vector<int> & vecbase = static_cast<Derived*>(ptr)->base ;
    std::vector<int> & vecderv = static_cast<Derived*>(ptr)->derv ;

    print_array(vecbase, "vecbase") ;
    print_array(vecderv, "vecderv") ;
    do_stuff(vecbase, 3) ;
    do_stuff(vecderv, 3) ;
    print_array(vecbase, "vecbase") ;
    print_array(vecderv, "vecderv") ;

    // Non-working
    *ptr = Derived() ;

    // Working but non-optimal
    // delete ptr ;
    // ptr = new Derived() ;

    print_array(vecbase, "vecbase") ;
    print_array(vecderv, "vecderv") ;
    do_stuff(vecbase, 5) ;
    do_stuff(vecderv, 5) ;
    print_array(vecbase, "vecbase") ;
    print_array(vecderv, "vecderv") ;

    return 0;
}

Current output:

vecbase => [ ]
vecderv => [ ]
vecbase => [ 3 3 3 ]
vecderv => [ 3 3 3 ]
vecbase => [ ]
vecderv => [ 3 3 3 ]  <=
vecbase => [ 5 5 5 5 5 ]
vecderv => [ 5 5 5 5 5 ]

Expected output:

vecbase => [ ]
vecderv => [ ]
vecbase => [ 3 3 3 ]
vecderv => [ 3 3 3 ]
vecbase => [ ]
vecderv => [ ] <=
vecbase => [ 5 5 5 5 5 ]
vecderv => [ 5 5 5 5 5 ]

[Edit by Peter:] Note that this is not slicing because *p is a Derived, even if its static type is Base.]

Peter - Reinstate Monica
  • 15,048
  • 4
  • 37
  • 62
Fritzip
  • 1,207
  • 8
  • 13
  • 3
    [What is object slicing?](/questions/274626/what-is-object-slicing) – cpplearner Apr 26 '17 at 13:40
  • 2
    `*ptr` has type `Base&`. `*ptr = Derived();` invoking Base::operator=(const Base&). And there you get slicing mentioned above. – Serikov Apr 26 '17 at 13:45
  • If you *know* the object pointed to by `ptr` is a `Derived` object then you could do `*dynamic_cast(ptr) = Derived();`. But it might be better to give `Base` a `virtual void clear();` method and override it in `Derived`. – cdhowie Apr 26 '17 at 14:31
  • 2
    Note that this is not slicing. It's a matter of not defining an adequate `virtual Base::operator=(const Derived &rhs)` which must be overridden in `Derived` to take care of the additional members. See http://tpcg.io/fxGfNT . – Peter - Reinstate Monica Oct 10 '18 at 07:00
  • It *is* interesting that calling a member function through the dereferenced pointer (in `*p = Derived()`, or in other words `(*p).operator=(Derived())`) does invoke the method defined in `Derived` if `p` actually points to a `Derived`. But then it is equivalent to `p->operator=(Derived())` which looks more virtual-prone ;-). And nobody would call "slicing!" if it were written thusly. – Peter - Reinstate Monica Oct 10 '18 at 07:07

0 Answers0