0

Let's say I have two abstract classes, A1 and A2. A1 has a function called foo(), A2 has a function called bar(). I create many different child classes of these base classes, say C1,C2,C3,..., that may or may not inherit A1 and/or A2. I now want to loop over all classes of type A1 and all classes of type A2 and call foo() resp bar(). My question is what is the best way to achieve this? My approach would be to use either smart pointers or vectors that hold instances of C1,C2,..., ie:

std::vector<C1> c1s;
std::vector<C2> c2s;
std::unique_ptr<C3> c3;
...

I then declare two integers, n_A1 and n_A2 that specify how many instances I have of each abstract class A1 and A2. I then define two arrays of pointers:

A1 **a1s = new A1*[n_A1];
A2 **a2s = new A2*[n_A2];

and then manually add all the addresses of the instances to these arrays. For example, if c1s has length 2, c2s has length 3, and if C1 inherits A1, C2 inherits A2, C3 inherits A1 and A2 I would do:

a1s[0]=&c1s[0];
a1s[1]=&c1s[1];
a2s[0]=&c2s[0];
a2s[1]=&c2s[1];
a2s[2]=&c2s[2];
a1s[2]=c3.get();
a2s[3]=c3.get();

So thus n_A1=3 and n_A2=4 and I can now loop over the arrays of addresses a1s and a2s and call the functions foo() or bar(). When deleting the instance holding all these objects, I just have to free the arrays a1s and a2s.

Being constantly recommended not to use raw pointers in C++, I wonder if this is a good way to solve this problem? Are there any risks with this approach? Is there a better way of doing this?

Jonathan Lindgren
  • 1,192
  • 3
  • 14
  • 31
  • 2
    Raw owning pointers are problematic, *"observer"* pointers are ok. So `std::vectora1s{&c1s[0], &c1s[0], c3.get()};` (Care have to be done for pointer validity though). – Jarod42 Feb 14 '19 at 10:59
  • 1
    "not to use raw pointers" is an unfortunate myth. "using raw owning pointers" is the evil – 463035818_is_not_an_ai Feb 14 '19 at 11:03
  • Highly recommend to read: [When should I use raw pointers over smart pointers?](https://stackoverflow.com/q/6675651/580083). An exemplary quote from the accepted answer: _"If there is no notion of ownership, **never** use smart pointers."_ – Daniel Langr Feb 14 '19 at 11:14
  • You can use the [observer pattern](https://codereview.stackexchange.com/questions/184702/implementation-of-observer-pattern-in-c14) – Amadeus Feb 14 '19 at 11:40
  • Q: _"I now want to loop over all classes of type A1 and all classes of type A2 and call foo() resp bar()."_ What if a class is both an A1 and an A2? Do you call both foo() and bar()? – YSC Feb 14 '19 at 12:15
  • 1
    Also, you ask a lot of questions (I count four). Which one should we answer? – YSC Feb 14 '19 at 12:18

1 Answers1

0
class IA
{
   virtual ~IA();
}

class A1 :public  IA
{
   virtual ~A1();
   virtual void foo();
}

class A2 :public  IA
{
   virtual ~A2();
   virtual void bar();
}

class C1 :public  A1
{
   virtual ~C1();
   virtual void foo();
}
class C2 :public  A2
{
   virtual ~C2();
   virtual void bar();
}
class C3 :public A1,public A2
{
   virtual ~C3();
   virtual void foo();
   virtual void bar();
}

int main()
{
  std::vector<IA*> AllAsObjects;
  AllAsObjects.push_back(new C1());
  AllAsObjects.push_back(new C2());
  AllAsObjects.push_back(new C3());
  for (IA* Obj :AllAsObjects)
  {
    if(dynamic_cast<A1*>(Obj))
      dynamic_cast<A1*>(Obj)->foo();
    if(dynamic_cast<A2*>(Obj))
      dynamic_cast<A2*>(Obj)->bar();
  }
}

I think that is what you need

*be aware that is self compiled

M. Khalil
  • 43
  • 1
  • 8
  • 1
    `IA` class should have virtual destructor. And, it would be better to use a vector of `std::unique_ptr`. – Daniel Langr Feb 14 '19 at 11:50
  • his question was about using raw pointers so of course i am adding virtual destructor, but using `unique_ptr` would be off point i think @DanielLangr – M. Khalil Feb 17 '19 at 09:09