通常,在C ++中看起来更可取的是,将参数带到多态对象的函数的代码会获取指向它的指针:
class Base {};
class DerivedA : public Base {};
class DerivedB : public Base {};
void OperateOnObject(Base* obj) {};
vector<Base*> objects;
objects.push_back(new DerivedA());
objects.push_back(new DerivedB());
for (size_t i=0; i<objects.size(); i++) {
OperateOnObject(objects[i]);
}
为什么OperateOnObject()
通常被编写为指向Base
而不是引用?切片是否存在潜在问题? (例如,vtable迷路了)
我已经看到了this response一个类似的问题,但它似乎没有解决同样的问题。
答案 0 :(得分:10)
切片当然没有问题 - 你的类不需要vtable,因为它们没有虚函数,但即使它们确实有它们,传递引用也不会复制对象,因此不会切片。
您可以通过指针完全通过引用进行虚拟调用。所以据我所知,没有实际的理由,只有风格。
也许这与多态对象通常由new
指针创建的事实有关,当然必须通过指针(或智能指针)存储在容器中,因为你可以没有参考的容器。然后,总是通过指针来操纵它们似乎更加一致。
另外,如果你想在OperateOnObject
之类的标准算法中使用for_each
,那么它必须接受容器的元素类型,这是一个指针,否则你必须包装它在一个执行取消引用的函数适配器中。标准C ++没有那个适配器,所以基于你的风格是一个麻烦的世界。
相关:看看如果OperateOnObject
接受引用会发生什么,并使用迭代器迭代向量:
for (vector<Base*>::iterator i = objects.begin(); i != objects.end(); ++i) {
OperateOnObject(**i);
}
第二次双向间接惹恼或混淆你,你将改变OperateOnObject
的签名; - )
顺便说一下,一些样式指南警告不要传递非const引用,无论该类型是否是多态基类,理由是你无法立即分辨传递引用和传递之间的区别。在呼叫站点读取代码时的值。因此,无论如何,他们都希望OperateOnObject
采用指针。
我个人认为这个论点有点弱 - 一个函数的名字应该大致告诉你它的作用,特别是像ChangeTheObject(my_object);
这样的陈述并没有如此巧妙地暗示我,因为它没有使用任何返回值,都必须改变其参数。但我接受的是,如果你正确地遵循一种风格,那么明确而一致地将变异者与纯粹的功能区分开来会有一些好处。
答案 1 :(得分:9)
引用不存在切片问题 - 在这方面,它们与指针一样好。除非你希望代码可以使用NULL
的语义(即传递“无”的能力),否则没有“硬”理由选择指针,如果你使用引用,那就不存在了。
我认为指针类型通常用作多态函数的参数来匹配集合的语义:因为你不能创建vector
个引用,所以你的代码最终必须取消引用从集合中获取的指针他们的功能。这可能很烦人。