0

My use case is the following. I have a pure abstract class and inherited classes like so:

class AbstractCell {
public:
   // data members
   virtual void fn () = 0;  // pure virtual functions
}

class DerivedCell1 : public AbstractCell {
public:
  // more data members
  void fn () {}  // implementation of all virtual functions
}

class DerivedCell2 : public AbstractCell {
public:
  // more data members
  void fn () {}  // implementation of all virtual functions
}

Now, I want to create an array of the abstract class as a member of another class.

class AbstractGrid {
public:
  AbstractCell m_cells [10][10];  //  this is illegal
  
  void printCells() {
      // accesses and prints m_cells
      // only uses members of AbstractCell
  }
}

class DerivedGrid1 : public AbstractCell {
public:
  DerivedCell1 m_cells [10][10];  // I want this class to use DerivedCell1 instead of AbstractCell
}

class DerivedGrid2 : public AbstractCell {
public:
  DerivedCell2 m_cells [10][10];  // I want this class to use DerivedCell2 instead of AbstractCell
}

How should I go about achieving this?

Constraints:

  1. For runtime efficiency, I want to use fixed-size arrays and not dynamic memory allocation (new or smart pointers).
  2. I want a solution other than using template classes.

I'm currently using templates, but I'm wondering if there's a better way.

7
  • 2
    Can you explain the perceived problem with templates? Commented Jan 22, 2022 at 16:46
  • 3
    "not dynamic memory allocation" Then don't use inheritance-based polymorphism. You can either use inheritance-based polymorphism or avoid dynamic allocation. You cannot have both. Commented Jan 22, 2022 at 16:49
  • 2
    For the instantiation problem, perhaps make AbstractGrid a template that gets passed the non-abstract derived cell types? It won't be using any polymorphism though, for that you must use poinster (or references). Commented Jan 22, 2022 at 16:50
  • 1
    Your two constraints will make any solution very awkward. Constraint #1 probably has an unwarranted assumption (hard to say without profiling optimized code). Constraint #2 will make any solution fragile. The part that noted as being illegal is illegal for a reason. The easy solutions violate constraints #1 and #2. Commented Jan 22, 2022 at 17:03
  • Thanks everyone! I suspected there wasn't a simple solution satisfying all my constraints. I think I'll just stick to templates. @HolyBlackCat The reason I would prefer avoiding templates is to (1) avoid having to put function definitions in header files, and (2) my IDE doesn't provide completion and type hints when using templated classes. Commented Jan 22, 2022 at 17:28

1 Answer 1

3

Abstract classes rely on virtual functions to be useful. The right function to be called is determined at runtime depending on the real type of the polymorphic object.

You cannot benefit of such polymorphism with an array of objects. Arrays require a type that is determined at compile-time and that can be instantiated. This is incompatible with abstract classes.

If you want an array with abstract classes, you have to go for an array of pointers. And typically, you'd use unique_ptr or shared_ptr, to avoid accidents in memory management. You can use new/delete if you prefer, but at your own risk.

If you love templates and are worried about performance of dynamic memory allocation, you may have a look at Alexandrescu's Modern C++ design.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.