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

the*_*ill 8 c++ polymorphism pointers reference

通常,在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]);
}
Run Code Online (Sandbox Code Playgroud)

为什么OperateOnObject()通常写入指针Base而不是引用?切片是否存在潜在问题?(例如,vtable迷路了)

我已经看到了对类似问题的回应,但它似乎没有解决同样的问题.

Ste*_*sop 10

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

您可以通过引用完全通过引用进行虚拟调用.所以据我所知,没有实际的理由,只有风格才有.

也许这与多态对象通常由指针创建的事实有关new,当然必须通过指针(或智能指针)存储在容器中,因为你不能有一个引用容器.然后,总是可以通过指针来操纵它们.

此外,如果你想OperateOnObject在标准算法中使用for_each,那么它必须接受容器的元素类型,这是一个指针,否则你必须将它包装在执行取消引用的函数适配器中.标准C++没有那个适配器,因此基于它的风格是一个麻烦的世界.

相关:看看如果OperateOnObject使用引用会发生什么,并使用迭代器迭代向量:

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

第二次双向间接惹恼或困惑你,你将改变签名OperateOnObject;-)

顺便说一句,一些样式指南警告不要传递非const引用,无论该类型是否是多态基类,理由是你不能立即告诉你传递引用和传值的区别在呼叫网站上阅读代码.所以OperateOnObject无论如何他们更愿意拿指针.

我个人认为这个论点有点弱 - 一个函数的名字应该大致告诉你它的作用,特别是一个声明就像ChangeTheObject(my_object);是不是那么巧妙地暗示我,因为它没有使用任何返回值,它必须改变它论点.但我接受的是,如果你正确地遵循一种风格,那么明确且一致地区分突变者与纯粹的功能有一些好处.


das*_*ght 9

引用不存在切片问题 - 在这方面,它们与指针一样好.除非您希望NULL代码可以使用语义(即能够传递"无",如果您使用引用则不存在),因此没有"硬"理由选择指针.

我认为指针类型通常用作多态函数的参数来匹配集合的语义:由于你不能创建vector引用,你的代码最终必须在将它们传递给函数之前取消引用从集合中获取的指针.这可能很烦人.