0

I created an abstract class and then created child classes that inherit this abstract class.

  class A{
       public:
       virtual A* clone() const = 0;
       virtual A* create() const = 0;
       ~virtual A(){};
       // etc.

  };

child classes

     class B: public A{};
     class C: public A{};

I then use an implicit conversion of a child class pointer to a base class pointer in the main function.

     int main(){

     B* pB = new B();
     C* pC = new C();

     A* pA = pB;     //converting a pointer to A, to a pointer to B
     A* pAA = pC;    //converting a pointer to A, to a pointer to C

I can now populate a vector with these classes using a pointer of type A and access the child classes via polymorphism.

    vector<A*> Pntr;

However I want each child class to take responsibility of its own memory release. I know that I can use unique pointers for this. The question is how do I implement this.

If I code it like this:

    pA = unique_ptr<A>(pB);
    pAA = unique_ptr<A>(pC);

Then I populate the vector like this:

    vector<unique_ptr<A>>Pointers;
    Pointers.push_back(move(pA));
    Pointers.push_back(move(pAA));

Not sure this will even work. And I am also confused about will actually be destroyed when the vector goes out of scope. Will the converted pointers pA and pAA simply be set to NULL or will the class objects be destroyed - which is my original intention. Some clarity needed.

1 Answers1

1

Why don't you just try to do it?

The example below presents a way in which you could create an Interface (your abstract base class) and two derived classes implementing that interface (Foo and Bar in this case).

You can then create a container of std::unique_ptr<Interface> (unique pointers to the abstract base class) and populate it using various methods and helper functions: emplace_back with std::make_unique, push_back with std::move, and so on.

After you run the example you will notice that the destructor gets called automatically --- that's the beauty of std::unique_ptr.

#include <cassert>
#include <memory>
#include <vector>
#include <iostream>

class Interface {
 public:
  virtual ~Interface() {
    std::cout << "Destroying object" << std::endl;
  }
  virtual void Method() const = 0;
};

class Foo // Foo "implements" or "offers access to" the Interface
    : public Interface {
 public:
  void Method() const override { // here we override Interface::Method
    std::cout << "Foo::Method" << std::endl;
  }
};

class Bar // Bar "implements" or "offers access to" the Interface
    : public Interface {
 public:
  void Method() const override { // here we override Interface::Method
    std::cout << "Bar::Method" << std::endl;
  }
};


int main() {
  // declare
  std::vector<std::unique_ptr<Interface>> objects;

  // populate
  objects.emplace_back(std::make_unique<Foo>());
  objects.emplace_back(std::make_unique<Bar>());
  objects.emplace_back(std::make_unique<Foo>());

  // another way to populate
  std::unique_ptr<Foo> pfoo(new Foo);
  objects.push_back(std::move(pfoo));

  // but be careful... pfoo now points to nullptr because you
  // moved ("transfered control of") the pointer to the
  // vector; pfoo no longer owns it (so it owns nothing; it is a
  // nullptr)
  assert(pfoo == nullptr);

  // you can iterate over all members by REFERENCE (otherwise you
  // would need to make copies, and you cannot copy a unique_ptr)
  for(const auto & pobject : objects) {
    pobject->Method();
  }

  // at exit you should see the calls to the destructor

  return 0;

}

Compile and run:

$ g++ example.com -std=c++14 -Wall -Wextra
$ ./a.out
Foo::Method
Bar::Method
Foo::Method
Foo::Method
Destroying object
Destroying object
Destroying object
Destroying object
Escualo
  • 40,844
  • 23
  • 87
  • 135