我应该如何在不使用 C++ 中的构造函数的情况下将值(不是指针)转换为子类?
Posted
技术标签:
【中文标题】我应该如何在不使用 C++ 中的构造函数的情况下将值(不是指针)转换为子类?【英文标题】:How should I cast a value (not a pointer) to a subclass without using a constructor in C++? 【发布时间】:2015-02-10 21:13:11 【问题描述】:我有以下类打算用作值类型(因为它们只存储一个整数):
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
的包装器,它为getptr
和getref
成员函数提供类型安全。同样,函数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
必须采用大小参数之类的。
【问题讨论】:
如果只存储整数,为什么需要这么复杂的脚手架?但是,如果您想对值类型进行类型擦除,您通常使用 Variant 或 Union 类型。 @MorphingDragon:这对问题并不重要,但如果你想知道,整数实际上是指向虚拟内存映射的指针,我想要类型安全的解引用(实际上,我正在使用 @ 987654337@ 等而不是getref
和 getptr
)。
查看我的评论编辑。
@Matt 如果我正确理解了您的代码的意图,请使用组合而不是继承。让 foo_t如何安全、合规地将 _make_foo() 的返回值从 _foo_t 转换为 foo_t,而不会产生任何开销?
你绝对不能安全地投射,因为你不知道向下投射是有效的。但是,在这种特殊情况下,由于我们的派生类型与基类型的大小相同,因此您可以避免:
template <typename T>
foo_t<T> make_foo()
return static_cast<foo_t<T>&>(_make_foo());
也就是说,虽然这在 CRTP 世界中是有意义的,但我不确定这是否有意义。
【讨论】:
我没想过要转换为引用,但它不起作用,因为_make_foo()
返回一个临时值,不能转换为引用:error: invalid static_cast from type ‘_foo_t’ to type ‘const foo_t<SomeObject>&’
。
如果您想知道,我最终选择了_foo_t
:template <typename T> explicit operator foo_t<T>() const return *static_cast<foo_t<T>*>(this);
中的模板化转换运算符,这已经足够相似了。【参考方案2】:
您可以概括您的类模板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:20.35 对象 3 - a:10.92,b:20.35更新
鉴于您的 cmets,我认为您所需要的只是:
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());
【讨论】:
这不是我的班级正在做的。它实际上并不包含任何东西,只是一个映射到虚拟地址的整数值。它不应该是一个存储容器。_foo_t
的原因是将大部分代码放在库中,而不是在头文件中,foo_t<T>
只是一个类型安全的包装器。
也许我很困惑。 _foo_t::getptr()
怎么知道Object1
或SomeObject
需要多少内存?它会从哪里获得内存?
这就是贴出点点滴滴代码的问题。您可以发布完整的相关代码,也可以在没有代码帮助的情况下解释您在做什么。
@Matt 这是 XY 问题。告诉我们您想要实现什么,而不是拘泥于这种次优架构。
您不能以符合标准的方式将基类对象视为派生类对象。我猜这就是您正在寻找的答案以上是关于我应该如何在不使用 C++ 中的构造函数的情况下将值(不是指针)转换为子类?的主要内容,如果未能解决你的问题,请参考以下文章
如何在构造函数中访问类变量以在不使用 C++ 中的 this 指针的情况下分配它们
如何在不使用 C++/C 中的阻塞函数的情况下将值从线程返回到主函数
如何在不复制的情况下将画布 imageData 传递给 emscripten c++ 程序?