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;
}