为什么指向基类的指针比引用更受欢迎?

时间:2012-05-11 10:45:47

标签: c++ pointers reference polymorphism

通常,在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一个类似的问题,但它似乎没有解决同样的问题。

2 个答案:

答案 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个引用,所以你的代码最终必须取消引用从集合中获取的指针他们的功能。这可能很烦人。