8

通常,在 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 丢失了)

我已经看到类似问题的回答,但它似乎并没有解决同样的问题。

4

2 回答 2

10

切片当然没有问题——你的类不需要 vtable,因为它们没有虚函数,但即使它们确实有它们,传递引用也不会复制对象,因此不会切片任何东西。

您可以像通过指针一样通过引用进行虚拟调用。据我所知,没有实际原因,只是为了风格。

也许这与多态对象通常由指针创建new的事实有关,当然必须通过指针(或智能指针)存储在容器中,因为您不能拥有引用容器。然后总是通过指针来操作它们似乎更一致。

此外,如果您想OperateOnObject在标准算法中使用for_each,那么它必须接受容器的元素类型,即指针,或者您必须将其包装在执行取消引用的函数适配器中。标准 C++ 没有那个适配器,所以在它的基础上建立你的风格是一个麻烦的世界。

相关:看看如果OperateOnObject需要一个引用会发生什么,并且你使用迭代器迭代你的向量:

for (vector<Base*>::iterator i = objects.begin(); i != objects.end(); ++i) {
    OperateOnObject(**i);
}

第 20 次双重间接使您烦恼或困惑时,您将更改OperateOnObject;-)的签名

顺便说一句,一些样式指南警告不要传递非 const 引用,无论该类型是否是多态基类,因为你不能立即区分传递引用和传递值之间的区别。 '正在调用站点读取代码。因此,无论如何,他们更愿意OperateOnObject接受指针。

就我个人而言,我认为这个论点有点弱——一个函数的名称应该大致告诉你它做了什么,特别是像这样的语句ChangeTheObject(my_object);并不那么微妙地暗示我,因为它没有使用任何返回值,它必须改变它争论。但我承认,如果你正确地遵循一种风格,那么清楚且一致地将突变器与纯函数区分开来会有一些好处。

于 2012-05-11T10:54:22.990 回答
9

引用不会出现切片问题 - 在这方面,它们与指针一样好。没有“硬”的理由偏爱指针,除非您希望NULL您的代码可以使用的语义(即传递“无”的能力,如果您使用引用则不存在)。

我认为指针类型通常用作多态函数的参数以匹配集合的语义:由于您无法进行 a vectorof 引用,因此您的代码最终将不得不取消引用从集合中获得的指针,然后再将它们传递给函数。这可能很烦人。

于 2012-05-11T10:55:13.497 回答