说我有
class Parent
{};
class ChildOne : Parent
{};
class ChildTwo : Parent
{};
void SomeMethod(std::vector<Parent*>& parents);
我理解为什么我无法将std::vector<ChildOne*>
作为参数传递给SomeMethod
,因为SomeMethod
可能是{<1}}:
void SomeMethod(std::vector<Parent*>& parents)
{
parents.push_back(new ChildTwo);
}
这将是无效的。
但为什么我不能将std::vector<ChildOne*>
作为参数传递给
void AnotherMethod(const std::vector<Parent*>& parents);
在这种情况下,我无法想到会出现什么问题,但我必须遗漏一些东西。
编辑:
为了澄清,我想知道为什么存在这种限制。在C#(例如)中,这将编译(使用IEnumerables)。我认为存在失败案例。
答案 0 :(得分:3)
你是对的,它可以在大多数常见平台上的和中使用。然而,这通常是一种可怕的蠕虫病毒。
考虑到标准不保证所有数据指针的大小相同(例如,有char*
大于int*
的平台,因为它们没有单独的可寻址字节)。事实上,您可以将指向派生的转换为指向基类的指针并不意味着此转换是微不足道的,并且不会影响内存中的表示。毕竟,只要多继承进入图片,即使这个转换开始涉及更改指针的值。
同时,模板通常非常不透明。我们知道std::vector<T*>
的合理实施将为所有T
的数据使用相同的布局,只要T*
的大小相同即可。但一般来说,模板可以根据其模板参数执行任何操作,并且数据布局完全不兼容。
更不用说专业化了 - 如果模板专门用于<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);
}
但使用风险自负。
答案 1 :(得分:2)
std::vector<ChildOne*>
和
std::vector<Parent*>
是两种不同/“无关”的类型。
答案 2 :(得分:0)
多年以后,我找到了一段&#34; c ++编程语言&#34;这回答了这个问题,第27.2.1节
&#34;逻辑上,我们将不可变set<Circle*>
视为不可变集,因为当我们无法更改集时,不会发生将不适当的元素插入集合的问题。也就是说,我们可以提供从c onst set<const Circle*>
到const set<const Shape*>
的转换。默认情况下,语言不会这样做,但是set的设计者可以。&#34;