0

For a class hierarchy like:

struct base { int i = 1; };
struct derived final : public base
{
    int j = 2;
    void f() { i = 2; }
}; 
// more derivations from base

I'd like a way to create an instance of derived but using an existing base instance. For example:

base b; // b.i == 1
{
derived d;
d.f(); // d.i == 2
}

Is there a way to set things up so that after calling d.f() the value of b.i is 2? As I've tried to indicate, the lifetime of derived is fairly short.

Conceptually, I want to make base look like derived for a little while, with "look like" meaning access to d.j. When I'm done, I want the changes made to d.i to "stick to" b.i. The obvious solution of base& b member variable doesn't work because accessing i requires different syntax: b.i instead of i.

Copying the derived instance back to base when I'm done would work; but that seems rather smelly.

{
derived d;
d.f(); // d.i == 2
b = d; // copy, YUCK!
}

But I really only want and need one instance of base.


What's actually going on is that I'm trying to simulate nested functions; but I don't want to change the syntax to access either i or j.

In pseudo-code, I want to do something like:

struct s final
{
   int i = 1;
   void f()
   {
      int j = 2;
      auto g = [&]();
   }
   // ... other code ...
   void f::g() { i = 10; j = 20; }
};

In other words, the actual code for the "local function" is away from where it's declared.

  • *"What's actually going on is that I'm trying to simulate nested functions;"*. lambda might help for that. – Jarod42 Sep 22 '21 at 14:38
  • I meant that solution (and question) from your link is from 2002. Currently, there are other solutions. – Jarod42 Sep 22 '21 at 14:43
  • 1
    Unclear what you can change in the code? is doing `b = d;` (with slicing) solve your issue? ((initial state and) changes done in `d` will be copied to `b`). – Jarod42 Sep 22 '21 at 14:46
  • And how do you use `s`? – Jarod42 Sep 22 '21 at 14:49
  • 1
    How complicated is your real `base`? Could you have references in `d` that refer to the members in your shared base object (e.g., `int &i = b.i;`) without deriving from `base` itself? – 1201ProgramAlarm Sep 22 '21 at 14:51
  • [Demo](http://coliru.stacked-crooked.com/a/079669e1a66a2b1b) with lambda, if that help for your inner function. – Jarod42 Sep 22 '21 at 14:54
  • Can you post the full pseudo code? (Notice that your pseudo code doesn't use `derived`/`base` at all :/, and in you first snippet, `d` is unrelated to `b`). – Jarod42 Sep 22 '21 at 14:59
  • You cannot define something at function scope outside of that function. – Jarod42 Sep 22 '21 at 15:08

1 Answers1

0

I don't see any way to share the same member variable of object b with a different object d that serves as a decorator/view of b, because different objects have different sets of values for member variables.

If derived is derived from base, then the base-object is part of every derived-object and you cannot destroy the derived-object without destroying the intrinsic base-object as well.

If derived is not derived from base, then you cannot replace variables that expect a base-object with an object of type derived in your code; any xxx.i in your code will either work for xxx being an object of type base or for xxx being an object of type derived, but not for both. So applying a common code containing xxx.i to objects of derived and objects of base will not work (unless you have a macro like #define impl_f(b) { (b).i = 2; }, but I don't thing that you think of reusable code in form of makros).

A way I could think of is a derived class that enforces to be initialized with a base-object and copies back the (changed) values to this base-object once derived is destroyed:

struct base {
    int i = 1;
    base() { }
    base(base &_b) { i = _b.i; }
};

struct derived_base : public base
{
    derived_base(base &_b) : base(_b), b(_b)  {  }
    ~derived_base() { b = *this; }
    
private:

    base &b;
};

struct derived1 final : public derived_base
{
    int j = 2;
    
    derived1(base &_b) : derived_base(_b) { }
    
    void f() { i = 2; }
};



int main() {

base b; // b.i == 1
cout << "b member i (should be 1):" << b.i << std::endl;

{
    derived1 d(b);
    cout << "initially, d member i should be the value of b.i, i.e. 1:" << d.i << std::endl;
    d.f(); // d.i == 2
    cout << "after f(), d member i (should be 2):" << d.i << std::endl;
}

cout << "lifetime of d ended; b has overtaken the values from d" << std::endl;
cout << "b member i (should now be 2, too):" << b.i << std::endl;

}
Stephan Lechner
  • 34,891
  • 4
  • 35
  • 58