我可以使用模板作为安全的解决方案来多态处理数组吗?

时间:2019-03-24 14:17:33

标签: c++ polymorphism

众所周知,对数组的项目进行多态处理是危险的,因为一般而言,基类和派生类的大小不同,并且指针算法很可能会失败。

void doSomethingOnBases(Base* bases, int numBases)
{
    for(int i = 0; i < numBases; i++)
    {
        bases[i].doSomething();
    }
}


//...
//...
Derived deriveds[60];    // declare 60 derived objects
doSomethingOnBases(deriveds, 60);    // will crash and burn
//...
//...

但是,如果我这样做了怎么办?

template <class X>
void doSomethingOnArray(X* arr, int numItems)
{
    for(int i = 0; i < numItems; i++)
    {
        arr[i].doSomething();
    }
}


//...
//...
Derived deriveds[60];    // declare 60 derived objects
doSomethingOnArray(deriveds, 60);    
//...
//...

在这种情况下,编译器将看到Derived*被传入并生成doSomethingOnArray(Derived*, int),这是一个精确的类型匹配,因此,没有指针算术错误。

如果我可以保证doSomethingOnArray()中取消引用的任何对象都具有doSomething()方法,这是一种伪造多态性的安全方法吗?

2 个答案:

答案 0 :(得分:2)

可以使用模板,但是另一种解决方案是传递Base** bases,在其中保存指向派生自Base的对象的指针的数组。

void doSomethingOnBases(Base** bases, int numBases)
{
    for(int i = 0; i < numBases; i++)
    {
        bases[i]->doSomething();
    }
}

这将允许您保留混合的派生对象的数组,而不仅仅是单个类型Derived的数组。

顺便说一句:请注意,如果要使用模板化解决方案,那么您甚至都不需要从Base继承。

答案 1 :(得分:1)

只要您像在第二个示例中那样,而不是像

doSomethingOnBases<Base>(deriveds, 60);

您应该没事。如果您想让它特定于数组,请考虑这样编写模板:

template <typename X, std::size_t N>
void doSomethingOnArray(X (&arr)[N])
{
    for(auto a = &arr[0]; a != &arr[0] + N; ++a)
        a->doSomething();
}

此版本的优点在于它不会真正被错误地调用。它只能在实际数组上使用,它会根据参数自动推断数组的大小和元素类型。

另外,请注意,您可以简单地使用基于范围的for循环

for (auto& a : arr)
    a->doSomething();

for (Base& b : arr)
    …

如果由于某种原因确实需要基类引用...