向上转换 const 向量
Posted
技术标签:
【中文标题】向上转换 const 向量【英文标题】:Upcasting a const vector 【发布时间】:2014-03-03 07:50:31 【问题描述】:说我有
class Parent
;
class ChildOne : Parent
;
class ChildTwo : Parent
;
void SomeMethod(std::vector<Parent*>& parents);
我明白为什么我不能将std::vector<ChildOne*>
作为参数传递给SomeMethod
,因为SomeMethod
可能是:
void SomeMethod(std::vector<Parent*>& parents)
parents.push_back(new ChildTwo);
这将是无效的。
但是为什么我不能将std::vector<ChildOne*>
作为参数传递给
void AnotherMethod(const std::vector<Parent*>& parents);
在这种情况下,我想不出会出什么问题,但我一定是错过了什么。
编辑:
为了澄清,我想知道为什么存在这个限制。在 C#(例如)中,这将编译(使用 IEnumerables)。我假设存在一个失败案例。
【问题讨论】:
如果允许可转换类型,这种转换会对性能产生严重影响。对于指针,无法断言类型安全(即,如果存在此功能,则转换vector<Parent*> -> vector<void*>
也将有效,因为指针不知道继承。这是一个严重的混乱。
【参考方案1】:
你说得对,它可以在这种特殊情况下和在最常见的平台上工作。但是,如果一般允许这样做,那将是一个可怕的蠕虫罐头。
考虑到标准不保证所有数据指针的大小相同(例如,有些平台char*
大于int*
,因为它们没有可单独寻址的字节)。您可以将派生指针转换 到基指针的事实并不意味着这种转换是微不足道的并且不会影响内存中的表示。毕竟,一旦多重继承进入画面,即使是这种转换也开始涉及更改指针的值。
同时,模板通常是相当不透明的。我们知道,只要T*
的大小相同,std::vector<T*>
的合理实现将对所有T
s 的数据使用相同的布局。但总的来说,模板可以根据其模板参数做任何事情,但数据布局完全不兼容。
更不用说专门化了——如果模板专门用于<ChildOne*>
,它可能完全不兼容。
是的,在某些情况下,对用Parent*
实例化的模板的特定实现 的 const 引用可能会被别名为用ChildOne*
实例化的同一模板。但这些都非常脆弱,在一般情况下,这种可替代性会导致无数错误。
如果您知道在您的平台上实现标准库并且使用您的类型是安全的,您可以为其创建一个转换函数:
template <class D, class S>
const std::vector<D*>& base_cast(const std::vector<S*> &src)
return reinterpret_cast<const std::vector<D*>&>(src);
但使用风险自负。
【讨论】:
【参考方案2】:std::vector<ChildOne*>
和
std::vector<Parent*>
是两种不同/“不相关”的类型。
【讨论】:
这并没有真正回答这个问题:为什么库的实现者必须这样做? @hivert 是的,它确实回答了这个问题。 “库的实施者”是什么意思?【参考方案3】:几年后,但我找到了“C++ 编程语言”的一部分来回答这个问题,第 27.2.1 节
"从逻辑上讲,我们将不可变的set<Circle*>
视为不可变集合,因为当我们无法更改集合时,不会出现在集合中插入不适当元素的问题。也就是说,我们可以提供从 c@987654322 的转换@ to const set<const Shape*>
。语言默认不这样做,但是set的设计者可以。”
【讨论】:
以上是关于向上转换 const 向量的主要内容,如果未能解决你的问题,请参考以下文章