Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 有没有一种方法可以通过引用来模拟向下投射_C++_Templates_C++11_Casting - Fatal编程技术网

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函数吗?天哪!我知道你在做什么,但我不明白为什么从编码的角度来看这会如此复杂。这些是结构而不是类,所以我认为在处理结构时,编译器会更智能一些。是的,结构是内在的