0

I have multiple classes with same function as below

class A
{
  void display()
  {
    // display something
  }
};

class B
{
  void display()
  {
    // display something two
  }
};

I want to store difference class at a list or a vector and loop to call the same function with same name

int main()
{
  A * a;

  B * b;

  //list or vector to store object

  std::vector < Something that can store different class > listofclass;

  listofclass.emplace_back(a);

  listofclass.emplace_back(b);

  for (int i = 0; i < listofclass.size(); i++)

  {

    listofclass[i].display();

  }
}

Is that possible to do like this? Because there is separate classes, having different purpose, and now i try to group them together Or there is other alternative way to achieve something like this

bolov
  • 72,283
  • 15
  • 145
  • 224
yuankuan
  • 1
  • 1

3 Answers3

4

If you control the definition of A and B, you can write a common base class, and have them inherit it.

class can_display {
public:
  virtual void display() = 0;
  virtual ~can_display() = default;
};

class A : public can_display 
{
  void display() override
  {
    // display something
  }
};

class B : public can_display 
{
  void display() override
  {
    // display something two
  }
};

int main()
{
  A a;

  B b;

  std::vector<can_display *> displayables;

  displayables.push_back(&a);

  displayables.push_back(&b);

  for (can_display * displayable : displayables)
  {
    displayable->display();
  }
}

As an alternative to changing the definition of A and B to inherit from a common base, you can have a wrapper that inherits.

template <typename T>
class can_display_impl {
  T * wrapped;
public:
  can_display_impl(T * wrapped) : wrapped(wrapped) {}
  void display() override { wrapped->display(); }
}

template <typename T>
std::unique_ptr<can_display> make_can_display(T & wrapped) {
  return std::make_unique<can_display_impl<T>>(&wrapped);
}

int main()
{
  A a;

  B b;

  std::vector<std::unique_ptr<can_display>> displayables;

  displayables.emplace_back(make_can_display(a));

  displayables.emplace_back(make_can_display(b));

  for (auto & displayable : displayables)
  {
    displayable->display();
  }
}
Caleth
  • 52,200
  • 2
  • 44
  • 75
0

You have two solutions for this problem:

  1. Use inheritance and just make a abstract class that will be a interface for your classes. In class A and class B just inherit from that interface and in std::vector hold pointer to base class.
#include <vector>
#include <iostream>
#include <memory>

class Interface_display {
public: 
    virtual void display() = 0; 
    virtual ~Interface_display(){}; 
};

class A : public Interface_display
{
public:

  void display() override 
  {
    std::cout << "Display from A\n";
  }
  ~A() override = default; 
};

class B : public Interface_display
{
public:

  void display() override
  {
    std::cout << "Display from B\n";
  }
  ~B() override = default;
};

int main(void)
{
    std::vector<std::unique_ptr<Interface_display>> v;

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

    for (const auto &element: v) {
        element->display();
    }
}
  1. And if you are using c++17, you could use std::variant and wrap objects of your class to std::variant:
#include <vector>
#include <iostream>
#include <variant>

class A
{
public:
  void display()
  {
    std::cout << "Display from A\n";
  }
};

class B
{
public:
  void display()
  {
    std::cout << "Display from B\n";
  }
};

int main(void)
{   
    using variant_t = std::variant<A, B>; 
    std::vector<variant_t> v;

    v.emplace_back(A());
    v.emplace_back(B());

    for (auto &element: v) {
        std::visit([](auto &x) { x.display(); }, element);
    }
}

https://wandbox.org/permlink/8VBmziWzafbPZk99

Marek R
  • 32,568
  • 6
  • 55
  • 140
GoRo3
  • 161
  • 5
-1

A way to solve this problem is by using polymorphism. You make a superclass, which contains a pure virtual version of this function and let both A and B inherit from this class. By doing this, you can dynamic_cast any pointer of type A or B to a superclass type, on which you have defined the display function.

This will get you something like this

class C {
public:
    virtual void display() = 0;

    virtual ~C() = default;
};


class A : public C {
public:
    void display() override {
        std::cout << "A" << std::endl;
    };

    ~A() override = default;
};


class B : public C {
public:
    void display(){
        std::cout << "B" << std::endl;
    };

     ~B() override = default;
};

So you can do:

C* c = new A();
// You can put the types of C* in the same list, and iterate over this list and do on each element
c->display();
delete c;
Arno Deceuninck
  • 320
  • 3
  • 10