Home > Blockchain >  C : Possibility to assign multiple Interfaces
C : Possibility to assign multiple Interfaces

Time:03-11

I ran into a strange situation, and I wonder if there is a better way to implement this. I would be very thankful for suggestions. It comes down to this simple core problem:

  //Interface I1 and I2 shall not be combined, since that makes logically no sense
class I1 {
public:
  virtual void foo() = 0;
};

class I2 {
public:
  virtual void bar() = 0;
};

//Some classes implements both interfaces I1 and I2 (some others don't, but that's not relevant here)
class A : public I1, public I2 {
public:
  void foo() override {};
  void bar() override {};
};

class B : public I1, public I2 {
public:
  void foo() override {};
  void bar() override {};
};

//Since there is no logically meaningful parent for I1 and I2, I have to do something like this,
//to access both interfaces of class A and B
struct pair_t {
  I1& accessViaI1;
  I2& accessViaI2;
};

A a;
B b;

std::deque<pair_t> items;

items.push_back({ a, a });
items.push_back({ b, b });

The code is working and because there are references used for the deque, the performance should be not too bad. But at least the last lines look very strange for me. Does anyone have an idea how to code this? Or maybe an suggestion for the general structure? The main problem is, I1 and I2 are logically totally separated and independent. But if an objects implements both, I need them both. Same as for class A and B, it makes no sense to combine them together (neither via inheritance nor as composition)

I can use C 11 and boost. Many thanks for your help in advance.

CodePudding user response:

To improve

items.push_back({ a, a });
items.push_back({ b, b });

into

items.push_back({ a });
items.push_back({ b });

You might add constructors to your pair_t

struct pair_t {
  pair_t(I1& accessViaI1, I2& accessViaI2) :
      accessViaI1(accessViaI1),
      accessViaI2(accessViaI2)
  {}

  template <typename T,
           typename std::enable_if<std::is_base_of<I1, T>::value
                                && std::is_base_of<I2, T>::value, int>::type = 0>
  pair_t(T& t): pair_t(t, t) {}

  I1& accessViaI1;
  I2& accessViaI2;
};

Demo

CodePudding user response:

You can write an interface I3 that extends both I1 and I2 like below.

class I3 : I1, I2 {
}

its body may be empty because this interface will just be a combination of I1 and I2. If you want to access the instances that are both instances of I1 and I2, you can hold them using I3 interface.

CodePudding user response:

try variant instead:

using variant = std::variant<A, B>;
variant a = A();
variant b = B();
std::deque<variant> items;
items.push_back(a);
items.push_back(b);

variant is valid since c 17, but boost may has this feature as well.

CodePudding user response:

You can define a class called MetaData and then you can make all your interfaces also extend MetaData class. MetaData class may be like below:

class MetaData {
    public:
       MetaData(string className);
       vector<string> getBaseClassNames();
    protected:
        vector<string> baseClassNames;
    private:
        MetaData(); //private constructor to prevent construction with no parameter
}

MetaData::MetaData(string className) {
    baseClassNames.add(className);
}

This is not the complete solution, but can be enhanced to solve the problem. The enhanced solution would access the same baseClassNames instance for all the interfaces of a class.

  • Related