Is it possible to convert Base& to Derived& without object copying or undefined behavior?

Problem: I have a class (PortableFoo) designed to be very portable. It contains a scoped class PortableBar. The surrounding codebase (call it Client A) requires both Foo and Bar to have a function that cannot be implemented portably, and Foo's implementation must call Bar's implementation. The following is a solution that compiles and works in GCC, but I know invokes undefined behavior when it casts the reference from base to derived:

//Code in portable codebase
class PortableFoo
{
public:
    int a = 1;
    class PortableBar
    {
    public:
        int b = 1;
    } bar;
};

//Code in Client A
#include <iostream>
class AdaptedFoo: public PortableFoo
{
public:
    int fancy_foo_func()
    {
        return a + ((AdaptedBar&)bar).fancy_bar_func();
    }
    
    class AdaptedBar: public PortableBar
    {
    public:
        int fancy_bar_func()
        {
            return b;
        }
    };
};

int main()
{
    AdaptedFoo foo;
    std::cout<<foo.fancy_foo_func(); //prints "2"
    return 0;
}

As in the example, it's no issue for me to simply construct objects as AdaptedFoo in the first place in ClientA, the problem is that AdaptedFoo.bar is still of type PortableBar. I know of three solutions to the problem but each have significant drawbacks:

  1. The above solution, with an undefined behavior reference cast that may cause a segmentation fault if sizeof(AdaptedBar) != sizeof(PortableBar). (In the real codebase, I have tested that it always causes a segmentation fault if there's a size mismatch, because I actually store a vector of Bars. The minimal example is not quite complex enough for the segfault to show up.)
  2. Make fancy_bar_func() virtual with an empty implementation in PortableBar. This is only a solution to the minimal example, my real problem has the additional complication that fancy_bar_func() must be templated, and templated functions cannot be virtual. (Specifically, it is the serialize() function used by Boost Serialization - the third party library demands it be a templated function.)
  3. Give AdaptedBar a constructor with the signature AdaptedBar(PortableBar&), allowing temporaries of type AdaptedBar to be constructed from references to PortableBar. The problem is that such a temporary must copy all the members of PortableBar, and in the real world, PortableBar is an extremely large object, so making temporary copies during serialization isn't suitable.

Question: Since solutions 2 and 3 fail compilation and system requirements respectively, the undefined behavior is my only known valid solution right now. Are there other approaches I'm missing that do not invoke UB?



Read more here: https://stackoverflow.com/questions/67940935/is-it-possible-to-convert-base-to-derived-without-object-copying-or-undefined

Content Attribution

This content was originally published by John at Recent Questions - Stack Overflow, and is syndicated here via their RSS feed. You can read the original post over there.

%d bloggers like this: