引用代码:
#include <vector>
#include <iostream>
class Func {
public:
virtual void call() {
std::cout<< "Func -> call()" << std::endl;
}
};
class Foo : public Func {
public:
void call() {
std::cout<< "Foo -> call()" << std::endl;
}
};
class Bar : public Func {
public:
void call() {
std::cout<< "Bar -> call()" << std::endl;
}
};
int main(int argc, char** argv) {
std::vector<Func> functors;
functors.push_back( Func() );
functors.push_back( Foo() );
functors.push_back( Bar() );
std::vector<Func>::iterator iter;
for (iter = functors.begin(); iter != functors.end(); ++iter)
(*iter).call();
}
运行该代码时,它会在我的计算机上产生以下输出:
$ ./test
Func -> call()
Func -> call()
Func -> call()
是否有任何方法可以确保在这种情况下调用正确的虚函数?我是 C++ 的新手,但我最好的猜测是:
(*iter).call();
它被转换为一个 Func
对象。这是正确的吗?
最佳答案
您应该使用 shared_ptr 或 unique_ptr 来保存多态类型集合的元素。
随着您现在编写代码,Foo 和 Bar 实例被强制(复制构造)为 Func 类型的实例以适合 vector 。 (原因是 vector 为了性能立即按固定大小的值存储其元素,但是多态子类具有任意大的大小,在编译时未知,因此它只能存储基类。)
这样更好:
int main(int argc, char** argv) {
vector<shared_ptr<Func>> functors;
functors.push_back( make_shared<Func>() );
functors.push_back( make_shared<Foo>() );
functors.push_back( make_shared<Bar>() );
for (auto functor : functors)
functor->call();
}
在上面,引用计数指针用于隐式共享 vector 中 Func 的异构子类。 (这种间接允许通过地址间接存储任意大小的 Func 子类。)
另外,您可能想看看 std::function 和 std::bind,而不是滚动您自己的仿函数类型。
另一件要看的事情是完美转发和可变参数模板。
更新:对于旧的编译器:
int main(int argc, char** argv) {
vector<std::tr1::shared_ptr<Func> > functors;
functors.push_back( std::tr1::make_shared<Func>() );
functors.push_back( std::tr1::make_shared<Foo>() );
functors.push_back( std::tr1::make_shared<Bar>() );
for (size_t i = 0; i < functors.size(); ++i)
functors[i]->call();
}
关于具有继承性的 C++ vector ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10154977/