Why isn't this method being overridden?
Asked Answered
R

2

6

In a project of mine I encountered this problem where the polymorphism seemingly doesn't work. Derived classes don't seem to override the base class, but no errors ocurr either.

This is a simplification of the code, but it generates the same problem. The usage of vector and unique_ptr is the same as in my project, I suspect that my usage of those is what's causing the problem.

I expect

void print() override 
{ 
    printf("B HEJ");
}

to override

virtual void print() 
{ 
    printf("A HEJ"); 
}

, but it doesn't. Why?

Here is the complete source code:

#include <iostream>
#include <string>
#include <memory>
#include <vector>

class A
{
public:
    virtual void print() 
    { 
        printf("A HEJ"); 
    }
};

class B : public A
{
public:
    void print() override { printf("B HEJ"); }
};

int main()
{
    std::vector<std::unique_ptr<A>> ass;
    ass.emplace_back(std::make_unique<A>(B()));
    ass[0]->print();
    std::cin.get();
}
Revolution answered 20/8, 2021 at 18:53 Comment(1)
Remember, make_unique makes a new object too.Ricci
M
9

You need to make_unique<B> and add a virtual destructor to the base class.

  • make_unique<B> creates a unique_ptr<B> that, if B is derived from A will be accepted by (moved into) a unqiue_ptr<A>.
  • make_unique<A>(B()) copy constructs an A from a B, slicing the B (only the A part of the default constructed B will be copied).
  • As long as the virtual method chain is preserved, the most derived method is called. Not having a virtual destructor makes sure that only the base class destructor is called when you have a vector of base class pointers. The result is more often than not catastrophic. You want the destructor(s) of the most derived classes to be called - so make the base class destructor virtual.
#include <iostream>
#include <string>
#include <memory>
#include <vector>

class A
{
public:
    virtual ~A() = default;
    
    virtual void print() 
    { 
        printf("A HEJ"); 
    }
};

class B : public A
{
public:
    void print() override { printf("B HEJ"); }
};

int main()
{
    std::vector<std::unique_ptr<A>> ass;
    ass.emplace_back(std::make_unique<B>());
    ass[0]->print();
}
Midian answered 20/8, 2021 at 18:57 Comment(0)
E
12

You have an error here:

 ass.emplace_back(std::make_unique<A>(B()));

This line creates a unique pointer to A, initializing it by copying from default-constructed B. It is equivalent with new A(B()) for naked pointers.

You need to create a unique pointer to B, so your code should look like:

 ass.emplace_back(std::make_unique<B>());

While on it, do not forget to add virtual destructor to A.

Epicarp answered 20/8, 2021 at 18:57 Comment(0)
M
9

You need to make_unique<B> and add a virtual destructor to the base class.

  • make_unique<B> creates a unique_ptr<B> that, if B is derived from A will be accepted by (moved into) a unqiue_ptr<A>.
  • make_unique<A>(B()) copy constructs an A from a B, slicing the B (only the A part of the default constructed B will be copied).
  • As long as the virtual method chain is preserved, the most derived method is called. Not having a virtual destructor makes sure that only the base class destructor is called when you have a vector of base class pointers. The result is more often than not catastrophic. You want the destructor(s) of the most derived classes to be called - so make the base class destructor virtual.
#include <iostream>
#include <string>
#include <memory>
#include <vector>

class A
{
public:
    virtual ~A() = default;
    
    virtual void print() 
    { 
        printf("A HEJ"); 
    }
};

class B : public A
{
public:
    void print() override { printf("B HEJ"); }
};

int main()
{
    std::vector<std::unique_ptr<A>> ass;
    ass.emplace_back(std::make_unique<B>());
    ass[0]->print();
}
Midian answered 20/8, 2021 at 18:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.