It is conceivable, for both Pascal and C, to have more than one string implementation side by side, so the developer can choose to use the best-fitting one.
In C++23, variant<> permits to do what Rust's typed enums introduced (e.g. Result sum type that is either a "real" result - with result type - or an error - with error type -, each strongly typed).
If you do that, a definition like
class IString { /* basic string functions */ };
class MiniString : public IString {};
class CZeroTerminatedString : public IString {};
class PascalString : public IString {};
class CppString : public IString {};
use String = std::variant<MiniString, CZeroTerminatedString, PascalString, CppString>; // define one type for all impl.
permits to define string functions that operate over the sum type String, and which use the methods defined in the interface IString, and which then work for all string implementations.
The developer can then pick the most suitable implementation, i.e. CMiniString for very, very short strings (that fit into 64 bits, so approx. <= 8 UTF-8 characters), CZeroTerminatedString (for char *co = "test\n"; zero-terminated old style C strings), CPascalStrings for strings that carry a length in s[0] or as a struct member or class field, and CppString as a wrapper for the C++ std::string that implements IString.
Sum types are a type-safe and memory-preserving way to do what in the older days was sometimes implemented using a "union {}" (which was not type-safe).