Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating an effective duplicate of a class that cannot interact with its base

Unreal Engine has a class called FVector which is a somewhat simple three component float vector.

One of the things that can be represented with that vector are coordinates. However, those coordinates can be in global space and local space.

There is a problem in the code base that I'm working on that it's not exactly clear which type of coordinate which functions take and it can be difficult to discern in what space a particular coordinate variable is when reading a random snippet of code.

I would like to have two types that behave the same way as FVector that represent those two cases, but cannot interact with one another, except through a explicit conversion function.

This way I can ensure that functions that take coordinates are explicit in what type of coordinate they take and the wrong type of coordinate cannot be passed to them by accident. Also when doing calculations with the coordinates, this would ensure that you cannot do operations between the two different types on accident.

What would be the best approach to this without outright duplicating the whole FVector class?

The solution should have minimal overhead and shouldn't make writing the code harder (when working with those types, users shouldn't really notice that they aren't FVectors until they try to pass them to the wrong function or add to a FVector). I'd like to avoid modifying the FVector base class, but would be willing to do it as long as behavior of FVector outside interacting with those types wouldn't change.

like image 648
Karlovsky120 Avatar asked Sep 02 '25 03:09

Karlovsky120


1 Answers

What would be the best approach to this without outright duplicating the whole FVector class?

You can provide a type aliases for the template class, which inherits from the FVector, as follows:

namespace internal
{
    // Main template class for coordinates
    template<typename SpaceTag>
    class TCoordinate final : public FVector
    {
    public:
        using FVector::FVector; // Inherit constructors
        // ... Add addtional FVector operations as needed
    };
}
// Type aliases for cleaner usage
using FGlobalCoordinate = internal::TCoordinate<struct GlobalSpaceTag>;
using FLocalCoordinate = internal::TCoordinate<struct LocalSpaceTag>;

// Conversion functions
FLocalCoordinate GlobalToLocal(const FGlobalCoordinate& Global);
FGlobalCoordinate LocalToGlobal(const FLocalCoordinate& Local);

See a live demo


Keep in mind that FVector might not have a virtual destructor(Most likely this would be the version OP is talking about), therefore assigning the allocated memory for the above two classes to FVector wouldn't be a good idea. Read more here: Is it okay to inherit implementation from STL containers, rather than delegate?

In that case, you have to use the FVector should be a data member to the TCoordinate class and delegate all the members required.

like image 165
JeJo Avatar answered Sep 04 '25 18:09

JeJo