我有一个函数,我需要指向Base
和Derived
类型的指针。我有一个应该能够处理两种容器类型的函数,因为它只调用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本身将在这里生成更多模板实例,这与我想要避免的完全相反。
答案 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>
是不同的类型。