0

I have two structs from a third party library so I can't change their layout. But I have two structs I wrote on my own which match their signature so I can add functions to them (again, but not their layout, therefore also no virtual functions). The structs are called Foo1 and Foo2. Both have the same member called _b, but at different offsets.

struct FooBase { };

struct Foo1 : FooBase
{
    int _a = 2;
    int _b = 1;
};

struct Foo2 : FooBase
{
    int _b = 2;
};

struct Wrap
{
    Wrap(const FooBase& x) : _x(x) { }
    FooBase& _x;
    int GetValue() { return /* MISSING */; }
};

I have a wrapper class called Wrap. I am looking for a way to return the value of _b without using virtual functions in the foo classes, since I can't change their size anymore.

Foo1 f1 = Foo1();
Wrap x = f1;
int a = x.GetValue(); // should return 1

Foo2 f2 = Foo2();
Wrap y = f2;
int b = y.GetValue(); // should return 2

Any ideas? I posted an approach in the comments but curious for a better solution.

HelloWorld
  • 2,392
  • 3
  • 31
  • 68
  • `Foo1::_b` and `Foo2::_b` are totally unrelated. It seems like there should be a way to do this statically, since they have the same name, but that's not how it works. If all `Foo` have a `int _b` data member, then it should be a member of `FooBase` instead. – François Andrieux Feb 27 '18 at 19:15
  • I could add a `std::function` to `Wrap` which would contain the function of `Foo1` or `Foo2` which returns the member. I don't feel like that's the best solution though – HelloWorld Feb 27 '18 at 19:15
  • 6
    Beware [slicing](https://stackoverflow.com/q/274626/10077)! Your `_x` needs to be a reference, not a value. A `FooBase` instance has neither `_a` nor `_b`. – Fred Larson Feb 27 '18 at 19:15
  • Yes, they would have the same name but otherwise are unrelated. That's what makes it so difficult to wrap my head around this – HelloWorld Feb 27 '18 at 19:16
  • @FredLarson: Indeed, thanks for spotting, fixed – HelloWorld Feb 27 '18 at 19:18
  • 1
    @HelloWorld Just pretend they have different names. Or even give them different names if it helps. – François Andrieux Feb 27 '18 at 19:18
  • @FrancoisAndrieux: I can't change their structure anymore, these are not my types – HelloWorld Feb 27 '18 at 19:20
  • 3
    When you construct a `Wrap` instance, do you have a concrete type to give the constructor, or just a `FooBase&`? – Fred Larson Feb 27 '18 at 19:21
  • @HelloWorld Then there is nothing you can do with a `FooBase`. You need to capture the concrete type in some way. – François Andrieux Feb 27 '18 at 19:22
  • @FrancoisAndrieux: I updated the first part of my question accordingly to your comment. Thanks a lot! @FredLarson: Wrap could have information, if it is `Foo1` or `Foo2` and the wrap class can also look how I want it too look like – HelloWorld Feb 27 '18 at 19:24

1 Answers1

6
struct Wrap
{
    Wrap(const Foo1& x) : _b(x._b) { }
    Wrap(const Foo2& x) : _b(x._b) { }
    int& _b;
    int GetValue() { return _b; }
};

Unless a class is needed, you can use a function template to the same effect.

template <typename Foo> int getValue(Foo const& foo)
{
   return foo._b;
}
R Sahu
  • 204,454
  • 14
  • 159
  • 270
Ishamael
  • 12,583
  • 4
  • 34
  • 52