C++ 有没有一种方法可以通过引用来模拟向下投射
因此,我有一些类似于这些结构的东西:C++ 有没有一种方法可以通过引用来模拟向下投射,c++,templates,c++11,casting,C++,Templates,C++11,Casting,因此,我有一些类似于这些结构的东西: struct Generic {} struct Specific : Generic {} 在某种程度上,我需要沮丧,即: Specific s = (Specific) GetGenericData(); 这是一个问题,因为我收到错误消息,指出没有用户定义的强制转换可用 我可以将代码更改为: Specific s = (*(Specific *)&GetGenericData()) 或者使用reinterpret_cast,它将是: Spe
struct Generic {}
struct Specific : Generic {}
在某种程度上,我需要沮丧,即:
Specific s = (Specific) GetGenericData();
这是一个问题,因为我收到错误消息,指出没有用户定义的强制转换可用
我可以将代码更改为:
Specific s = (*(Specific *)&GetGenericData())
或者使用reinterpret_cast,它将是:
Specific s = *reinterpret_cast<Specific *>(&GetGenericData());
Specific s=*重新解释强制转换(&GetGenericData());
但是,有没有办法让它更干净?也许使用宏或模板
我看了这篇文章,我认为它有一些相似之处,但不确定如何为我的案例重写它。我真的不想把事情定义为SmartPtr。我宁愿保持对象的原样。您使用的
GetGenericData()
会返回一个Generic
按值,在这种情况下,转换为特定的
将由于以下原因而不安全
要执行您想执行的操作,应使其返回指针或引用:
Generic* GetGenericData();
Generic& GetGenericDataRef();
然后您可以执行一个演员阵容:
// safe, returns nullptr if it's not actually a Specific*
auto safe = dynamic_cast<Specific*>(GetGenericData());
// for references, this will throw std::bad_cast
// if you try the wrong type
auto& safe_ref = dynamic_cast<Specific&>(GetGenericDataRef());
// unsafe, undefined behavior if it's the wrong type,
// but faster if it is
auto unsafe = static_cast<Specific*>(GetGenericData());
//safe,如果它实际上不是一个特定的*
自动安全=动态强制转换(GetGenericData());
//对于引用,这将抛出std::bad_cast
//如果你试错了类型
auto&safe_ref=动态_cast(GetGenericDataRef());
//不安全、未定义的行为如果类型错误,
//但如果是的话,速度会更快
自动不安全=静态_转换(GetGenericData());
因此,第一步是认识到您有一个动态问题。存储状态的性质根据动态信息进行更改
struct GenericState { virtual ~GenericState() {} }; // data in here
struct Generic;
template<class D>
struct GenericBase {
D& self() { return *static_cast<D&>(*this); }
D const& self() const { return *static_cast<D&>(*this); }
// code to interact with GenericState here via self().pImpl
// if you have `virtual` behavior, have a non-virtual method forward to
// a `virtual` method in GenericState.
};
struct Generic:GenericBase<Generic> {
// ctors go here, creates a GenericState in the pImpl below, or whatever
~GenericState() {} // not virtual
private:
friend struct GenericBase<Generic>;
std::unique_ptr<GenericState> pImpl;
};
struct SpecificState : GenericState {
// specific stuff in here, including possible virtual method overrides
};
struct Specific : GenericBase<Specific> {
// different ctors, creates a SpecificState in a pImpl
// upcast operators:
operator Generic() && { /* move pImpl into return value */ }
operator Generic() const& { /* copy pImpl into return value */ }
private:
friend struct GenericBase<Specific>;
std::unique_ptr<SpecificState> pImpl;
};
struct GenericState{virtual~GenericState(){};//这里有数据吗
结构泛型;
模板
结构通用库{
D&self(){return*static_cast(*this);}
D const&self()const{return*static_cast(*this);}
//在此处通过self().pImpl与GenericState交互的代码
//如果您有“虚拟”行为,请将非虚拟方法转发给
//GenericState中的“virtual”方法。
};
结构泛型:泛型库{
//CTOR在这里,在下面的pImpl中创建一个GenericState,或者其他什么
~GenericState(){}//不是虚拟的
私人:
friend结构GenericBase;
std::唯一的ptr pImpl;
};
结构特定状态:GenericState{
//这里的具体内容,包括可能的虚拟方法重写
};
特定于结构:GenericBase{
//不同的CTOR在pImpl中创建特定状态
//上行操作员:
运算符Generic()&&{/*将pImpl移动到返回值*/}
运算符Generic()常量&{/*将pImpl复制到返回值*/}
私人:
friend结构GenericBase;
std::唯一的ptr pImpl;
};
如果希望能够复制,请在GenericState
中实现virtual GenericState*clone()const
方法,并在SpecificState
中以协变方式覆盖它
我在这里所做的是正则化类型(如果我们不支持move,则半正则化)。特定类型和泛型类型是不相关的,但是它们的后端实现细节(GenericState和SpecificState)是相关的
主要通过CRTP和GenericBase
避免接口重复
向下广播现在可以涉及动态检查,也可以不涉及动态检查。您将通过pImpl
并将其覆盖。如果在右值上下文中完成,它会移动——如果在左值上下文中,它会复制
如果愿意,可以使用共享指针而不是唯一指针。这将允许非复制非移动铸造。好的,经过一些额外的研究,我想知道这样做有什么错:
struct Generic {}
struct Specific : Generic {
Specific( const Generic &obj ) : Generic(obj) {}
}
如果我错了,请纠正我,但这可以使用隐式复制构造函数工作
假设是这样,我可以避免写一个,并且自动执行铸造,现在我可以写:
Specific s = GetGenericData();
当然,对于大型对象,这可能不是一个好主意,但对于较小的对象,这是一个“正确”的解决方案吗?我假设您的数据很简单
struct Generic {
int x=0;
int y=0;
};
struct Specific:Generic{
int z=0;
explicit Specific(Generic const&o):Generic(o){}
// boilerplate, some may not be needed, but good habit:
Specific()=default;
Specific(Specific const&)=default;
Specific(Specific &&)=default;
Specific& operator=(Specific const&)=default;
Specific& operator=(Specific &&)=default;
};
鲍勃是你叔叔。intz
有一个默认的初始值设定项有点重要,因此我们不必在from父ctor中重复它
我使thr ctor显式,因此它将仅显式调用,而不是意外调用
这是一个适用于简单数据的解决方案。。。。你是说沮丧?啊!我在玩向上和向下投射,我的例子以向下投射结束…是的。向下转换。为
Specific
编写一个构造函数,该构造函数接受Generic const&
或Generic&&
(所谓的转换构造函数)。继承树的根在天上,叶子在地上。为什么不定义您自己的用户定义的从常规到特定的转换呢?作为特定于运算符、方法、自由转换函数或特定对象上的构造函数?应该注意的是,返回引用需要函数保持对象的活动状态,而返回指向自由存储内存的原始指针通常是一个非常糟糕的主意。@KonradRudolph。。。或者只是指针/返回某个已经存在的引用。这就是我所说的“需要函数保持对象的活动性”的意思。无论如何,这在某些情况下很有效,但在其他情况下则完全无效。请注意,dynamic\u cast
仅在Generic
是多态的情况下有效(这不是OP当前编写的情况,可以添加一个虚拟析构函数来修复)。因此,请尝试您的dynamic\u cast示例,我明白了:运行时动态_cast的操作数必须有一个多态类类型@Barry,我对你关于“…或只是指针/返回某个已经存在的引用的评论很感兴趣。在这种情况下会是什么样子?”我会将指针传递到GetGenericData函数吗?天哪!我知道你在做什么,但我不明白为什么从编码的角度来看这会如此复杂。这些是结构而不是类,所以我认为在处理结构时,编译器会更智能一些。是的,结构是内在的