说我有

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)。我假设存在一个失败案例。

最佳答案

您是对的,它可以在这种情况下和大多数常见平台上运行。但是,一般情况下允许使用这种蠕虫会很可怕。

考虑到该标准并不能保证所有数据指针的大小都相同(例如,在有些平台上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);
}

但是使用后果自负。

08-28 04:31