避免转换容器的元素指针类型

时间:2017-01-08 18:03:29

标签: c++ casting containers

我有一个函数,我需要指向BaseDerived类型的指针。我有一个应该能够处理两种容器类型的函数,因为它只调用Base中定义的所有虚函数。

如果直接给出元素指针就没有问题,如:

void Func(Base*);
Derived* d;
Func(d);  // works perfect

但是有一个容器类型,它变得丑陋和危险。当且仅当容器类型对于两种指针类型完全等效时,转换才会起作用。这通常是正确的,因为标准容器的所有已知实现都实现了从void*派生的指针类型,以尽量减少占用空间。

#include <iostream>
#include <vector>

class Base
{   
    public: virtual void Func() {std::cout << "Base" << std::endl; }
};  

class Derived: public Base
{   
    public:
        void Func() override { std::cout << "Derived" << std::endl; }
        void MoreFunc(){ std::cout << "SomeMoreFunc" << std::endl; } 
};  

// This function should "eat" also vector<Derived*>
// this can be simply done by using templates, 
// but results in doubling the code in memory while
// two instances will be created with exact the same
// content and they will not be optimized away ( gcc ).
void DoSomething( std::vector<Base*>& vec )
{   
    for ( auto& el: vec ) { el->Func();}   
}   

int main()
{   
    std::vector< Base*> vecBase;
    vecBase.push_back( new Base );
    vecBase.push_back( new Base );

    std::vector< Derived*> vecDerived;
    vecDerived.push_back( new Derived );
    vecDerived.push_back( new Derived );

    DoSomething( vecBase );
    DoSomething( (std::vector<Base*>&)vecDerived ); // that cast I want to avoid!

    for ( auto& el: vecDerived ) { el->MoreFunc(); }   
}   

如何在这里避免矢量元素类型的错误转换? 是否可以使用容器的完整副本,但也会浪费代码和运行时间。

是否存在针对此类问题的“典型”解决方案?

是的,内部的DoSomething比最小的例子中给出的更复杂。所以简单地将for()移除到foreach / lambda是没有机会的,并且从外部调用DoSomething中的函数并不符合我的真实世界问题。而且必须记住,for_each本身将在这里生成更多模板实例,这与我想要避免的完全相反。

1 个答案:

答案 0 :(得分:2)

您可以使用<algorithm>中的auto func = [](Base *ptr) { ptr->Func(); }; std::for_each(vecBase.begin(), vecBase.end(), func); std::for_each(vecDerived.begin(), vecDerived.end(), func); 和lambda来执行此操作:

void DoSomething(Base* ptr) {   
    ptr->Func();
}

或者按照以下方式定义您的功能:

std::for_each

并将其与std::for_each(vecBase.begin(), vecBase.end(), DoSomething); std::for_each(vecDerived.begin(), vecDerived.end(), DoSomething);

一起使用
std::for_each

两种情况都没有模板。
嗯,说实话,代码中没有模板。 DoSomething是一个功能模板,但DoSomething赢了。不确定它是你在寻找什么。

评论后修改

完全避免使用模板的最佳方法是将循环从Base *中取出 在这种情况下,任何接受data的函数都可以 另一方面,如果你想在你的函数中进行迭代,可能你无法通过传递容器(模板)或传递两个迭代器(模板)或基于假设(冒险)进行花哨演员表。 / p>

请注意,向量的成员函数size返回指向底层数组的指针。如果与Base **结合使用,您将拥有迭代元素所需的所有内容 无论如何,在您的情况下,Derived **Derived **是不同的野兽,您不能简单地将Base **传递给接受std::for_each的函数。

任何尝试使用标准库中的函数(作为示例std::vector<Base *>)都可能以某种方式使用模板函数结束。

这是因为std::vector<Derived *><div class="flyout"></div> 不同的类型。