First of all:

I ask this question just out of curiosity, to understand what's really happening. I don't use in production code like this so I don't want to see answers suggesting another solution.

Having this code:

class Base{
public:
    virtual void copy(){}
};

class Derived: public Base{
public:
    void copy(){
        Base a1;
        this->Base::Base(a1);//explicit call to base copy constructor
    }
};

I know that for some cases it is not good to call explicitly the copy constructor.(when classes have members allocated dynamically, because the reference to that memory area will be lost and it will not be freed anymore).

For the bellow example I don't see any direct problem for calling the base copy constructor. At the first sight I would think that the base sub-object must be reinitialized when copy() method is called.

int main(){
    Base** _a = new Base*;
    _a[0] = new Derived(10);
    Derived* b = dynamic_cast<Derived*>(_a[0]);
    assert(b);//<===true
    _a[0]->copy();
    //t is still available and can be accessed through b
    std::cout<<b->t;//correct: 10
    b = (Derived*)_a[0];
    std::cout<<b->t;//correct: 10
    b = dynamic_cast<Derived*>(_a[0]);
    assert(b);//<===false       
}

However the second assert fails. Can someone explain this behaviour? Why is this happening ? Is typeid lost when calling base copy constructor?

I compiled the code with Visual Studio 2012.

有帮助吗?

解决方案

Constructor before class members initialization set the vptr pointer to the virtual function table of that class. Manually calling constructor of parent class you make derived class vptr point to vtable of the parent class.

其他提示

Well, when you call Base::Base(const Base&), you are creating a new object of type Base in the memory allocated for your object of type Derived. After that, all virtual functions, for instance, will point to their Base:: implementations.

If you want to reinitialize your object, you must call the constructor of the derived type Derived::Derived(const Derived&), you can't just reinitialize part of it.

Aside:
You can make the reinitializetion correct by first destructing the object:

this->~Derived();    //cleanly destruct the object
this->Derived::Derived(...);    //rebuilt the object in place
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top