Home > Net >  Is there a way to make a derived instance use an existing base instance
Is there a way to make a derived instance use an existing base instance

Time:09-23

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.

CodePudding user response:

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;

}
  • Related