如果不使用C++中的构造函数,我应该如何将值(而不是指针)强制转换为子类

How should I cast a value (not a pointer) to a subclass without using a constructor in C++?

本文关键字:指针 子类 转换 C++ 构造函数 我应该 如果不      更新时间:2023-10-16

我有以下类打算用作值类型(因为它们只存储一个整数):

class _foo_t
{
    friend _foo_t _make_foo();
private:
    int foo;
    _foo_t(int foo) : foo(foo) {}
protected:
    void *getptr() const; // defined in .cpp
};
template <typename T>
class foo_t : public _foo_t
{
public:
    T *getptr() const { return (T*)_foo_t::getptr(); }
    T &getref() const { return *(T*)_foo_t::getptr(); }
};
_foo_t _make_foo(); // defined in .cpp
template <typename T>
foo_t<T> make_foo()
{
    return _make_foo(); // What kind of cast do I need here?
}

foo_t<T>只是_foo_t的包装器,为getptrgetref成员函数提供类型安全性。同样,函数make_foo()只是_make_foo<T>()的一个包装器。由于foo_t<T>_foo_t的子类,不添加任何字段,也没有虚拟成员,因此foo_t<T>对象在内存中看起来应该与_foo_t对象完全相同,并且我不希望这里有构造函数调用的开销。如何将_make_foo()的返回值从_foo_t安全、合规地转换为foo_t<T>而不产生任何开销?

编辑:

根据请求,以下是上面的一些示例用法:

class SomeObject { /* ... */ };
foo_t<SomeObject> obj = make_foo<SomeObject>();
new (obj.getptr()) SomeObject();
obj.getref().doSomething();

实际上,make_foo必须采用一个大小参数或其他参数。

如何安全、兼容地将_make_foo()的返回值从_foo_t强制转换为foo_t而不产生任何开销?

您肯定无法安全地投射,因为您不知道向下投射是有效的。然而,在这种特殊情况下,由于我们的派生类型与基本类型的大小相同,您可以使用

template <typename T>
foo_t<T> make_foo()
{
    return static_cast<foo_t<T>&>(_make_foo());
}

也就是说,虽然这在CRTP世界里是有意义的,但我不确定它在这里是否有意义。

您可以将类模板foo_t泛化为能够容纳任何数据类型,而不依赖于_foo_t。你可以使用:

template <typename T> class foo_t 
{
   public:
      char data[sizeof(T)];
      T *getptr() const { return (T*)data; }
      T &getref() const { return *(T*)data; }
};
template <typename T>
foo_t<T> make_foo()
{
   return foo_t<T>();
}

下面是一个演示其用法的示例程序:

#include <iostream>
#include <new>
template <typename T> class foo_t 
{
   public:
      char data[sizeof(T)];
      T *getptr() const { return (T*)data; }
      T &getref() const { return *(T*)data; }
};
template <typename T>
foo_t<T> make_foo()
{
   return foo_t<T>();
}
struct Object1
{
   int a;
   int b;
};
struct Object2
{
   int a;
   double b;
};
struct Object3
{
   double a;
   double b;
};
int main()
{
   foo_t<Object1> obj1 = make_foo<Object1>();
   new (obj1.getptr()) Object1();
   obj1.getref().a = 10;
   obj1.getref().b = 20;
   std::cout << "Object1 - a:" << obj1.getref().a << ", b: " << obj1.getref().b << std::endl;
   foo_t<Object2> obj2 = make_foo<Object2>();
   new (obj2.getptr()) Object2();
   obj2.getref().a = 10;
   obj2.getref().b = 20.35;
   std::cout << "Object2 - a:" << obj2.getref().a << ", b: " << obj2.getref().b << std::endl;
   foo_t<Object3> obj3 = make_foo<Object3>();
   new (obj3.getptr()) Object3();
   obj3.getref().a = 10.92;
   obj3.getref().b = 20.35;
   std::cout << "Object3 - a:" << obj3.getref().a << ", b: " << obj3.getref().b << std::endl;
   return 0;
}

程序输出:

对象1-a:10,b:20对象2-a:10,b:2.35对象3-a:10.92,b:2.35

更新

鉴于您的评论,我认为您所需要的只是:

template <typename T>
class foo_t : public _foo_t
{
   public:
      // Make sure you can use all of the base class
      // constructors in this class.
      using _foo_t::_foo_t;
      T *getptr() const { return (T*)_foo_t::getptr(); }
      T &getref() const { return *(T*)_foo_t::getptr(); }
};
template <typename T>
foo_t<T> make_foo()
{
   // Construct a foo_t<T> using a _foo_t and return it.
   return foo_t<T>(_make_foo());
}