0

I am really confused about polymorphic pointers. I have 2 classes derived from an interface as shown below code.

#include <iostream>

using namespace std;

class Base  {

public:
    virtual ~Base() { }
    virtual void addTest() = 0;
};

class B: public Base {

public:
    B(){}
    ~B(){}

    void addTest(){
        cout << "Add test B\n";
    }
};
class C: public Base {

public:
    C(){}
   ~C(){}

    void addTest(){
        cout << "Add test C\n";
    }
private:   
    void deleteTest(){
        
    }
    
};

int main()
{
    Base *base = new B();
    base->addTest();
    base = new C();
    base->addTest();
    return 0;
}

I want to change the pointer dynamically according to a condition at run time to use the same pointer with different kinds of scenarios.

Derived classes are different from each other, so what happens in memory when the polymorphic pointer object changes?

If that usage is not good practice, how can I change the polymorphic pointer object dynamically at the run time?

Hakkı
  • 3
  • 2
  • What is the question? Is this the question? "what happens in memory when the polymorphic pointer object changes?" – user253751 Apr 06 '22 at 14:54
  • 1
    I suspect that you're assuming that it is much more complicated than it is. All that happens is that `base` is assigned a different value - the location of the newly-created `C` - instead of its original value. That is, it is no more complicated than `int x = 1; x = 2;`. – molbdnilo Apr 06 '22 at 14:54
  • @user253751 yes, one of the questions is that. – Hakkı Apr 06 '22 at 15:16
  • Well this is *a* question not more than one question – user253751 Apr 06 '22 at 15:17

1 Answers1

0

It's perfectly fine to change what a pointer points to. A Base* is not an instance of Base, it is a pointer that points to an instance of a Base (or something derived from it -- in this case B or C).

Thus in your code, base = new B() sets it to point to a new instance of a B, and then base = new C() sets it to point to a new instance of a C.

Derived classes are different from each other, so what happens in memory when the polymorphic pointer object changes?

Because Base* points to an instance of a Base, all this is doing is changing which instance (or derived instance) Base* points to. In effect, it just changes the memory address of the pointer.

From that Base* pointer, you still have access to anything defined in that Base class -- which still allows polymorphic calls to functions satisfied by derived types if the function is defined as virtual.

The exact mechanism for how this is dispatched to derived types is technically an implementation-detail of the language, but generally this is done through a process called double-dispatch, which uses a "V-Table". This is additional type-information stored alongside any classes that contain virtual functions (it's conceptually just a struct of function pointers, where the function pointers are satisfied by the concrete types).

See: Why do we need a virtual table? for more information on vtables.


What is problematic, however, is the use of new here. new allocates memory that must be cleaned up with delete to avoid a memory leak. By doing the following:

Base *base = new B();
base->addTest();
base = new C(); // overwriting base without deleting the old instance
base->addTest();

The B object's destructor is never run, no resources are cleaned up, and the memory for B itself is never reclaimed. This should be:

Base *base = new B();
base->addTest();
delete base;
base = new C(); // overwriting base without deleting the old instance
base->addTest();
delete base;

Or, better yet, this should be using smart-pointers like std::unique_ptr to do this for you. In which case you don't use new and delete explicitly, you use std::make_unique for allocation, and the destructor automagically does this for you:

auto base = std::make_unique<B>();
base->addTest();
base = std::make_unique<C>(); // destroy's the old instance before reassigning
base->addTest();

This is the recommended/modern way to write dynamic allocations

Human-Compiler
  • 11,022
  • 1
  • 32
  • 59
  • 1
    I feel like this answer focuses too much on memory leaks and not enough on polymorphism. While the memory leak is a problem, I want to be clear that `delete` and `make_unique` aren't part of polymorphism. – user253751 Apr 06 '22 at 14:57
  • @user253751 That's fair; I've expanded on the polymorphic aspect, though IMO the real important part of the answer is that a `Base*` is a pointer and not an instance of `Base` specifically. – Human-Compiler Apr 06 '22 at 15:07