Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

inheritance and memcpy - How is it work together?

I have this code:

#include <iostream>
#include <string>
#include <cstring>

class Animal
{
public:
    Animal(const std::string &name) : _name(name)
    {
    }
    virtual void Print() const = 0;
    virtual ~Animal() {}
protected:
    std::string _name;
};

class Dog : public Animal
{
public:
    Dog(const std::string &name, const std::string &dogtype) : Animal(name), _dogtype(dogtype)
    {
        Print();
    }
    void Print() const
    {
        std::cout << _name << " of type " << _dogtype << std::endl;
    }
private:
    std::string _dogtype;
};

class Cat : public Animal
{
public:
    Cat(const std::string &name, int weight) : Animal(name), _weight(weight)
    {
        Print();
    }
    virtual void Print() const
    {
        std::cout << _name << " of weight " << _weight << std::endl;
    }
    virtual ~Cat(){}
private:
    int _weight;
};

class Tiger : public Cat
{
public:
    Tiger(const std::string &name, int weight, double speed) : Cat(name, weight), _speed(speed)
    {
        Print();
    }
    void Print() const
    {
        std::cout << _name << " speed " << _speed << std::endl;
    }
    virtual ~Tiger(){std::cout << "Tiger's dtor" << std::endl;}
private:
    int _speed;
};

int main()
{
    Animal *a = new Tiger("theRealKing", 3, 40.5);
    Cat *c = new Cat("silvester", 4);
    memcpy(c, a, sizeof(Cat));
    c->Print(); /// ------------------------
    delete a;
    delete c;
    return 0;
}

in the line : c->Print(): the line before that c became a tiger so why does it print me this line : Ross with speed 135081 insted of Ross with speed 3 why there is a memory problem ? why does it call the print method of tiger and not of cat ?

like image 341
John Oldman Avatar asked Sep 19 '25 15:09

John Oldman


2 Answers

It doesn't work together.

Using memcpy on these objects produces undefined behavior, the Standard permits anything to happen.

It isn't inheritance per se that is causing you problems, but the presence of virtual member functions or custom constructor/destructor. These make your objects lose the trivially-copyable classification that is required when using memcpy.

Your class isn't trivially-copyable for a second reason -- it contains a member of type std::string which is not trivially-copyable.

In practical terms, when you perform a bitwise copy of a std::string subobject, you end up with two pointers to the same memory, and both string objects will try to free this pointer. That will crash your program. If using memcpy on a v-table hasn't done so earlier.

But when you mix in optimizations, even weirder things can happen. That's what undefined behavior means.

like image 187
Ben Voigt Avatar answered Sep 22 '25 06:09

Ben Voigt


You should avoid using memcpy for objects in c++, use the copy constructor instead.

like image 29
Ivaylo Strandjev Avatar answered Sep 22 '25 05:09

Ivaylo Strandjev