我有一个功能
void h(A const a){...};
如果我这样做,行为是否可能会改变:
void h(A const &a){..same body as above..};
您可以根据需要自由定义类型 A。当然。
在第一次重载中,h 不能改变 'a'。它在“h”的主体中用于所有目的 const。但是,这涉及复制构造函数来复制初始化“a”。
因此,在第一种情况下,它需要“A”中的可访问复制构造函数。出于同样的原因,它需要 A 中的可访问析构函数。
在第二种情况下,不需要复制初始化,因此不需要“A”的可访问复制构造函数/析构函数。
此外,在第一种情况下,如果“A”的派生对象作为参数传递,“a”将进行“切片”。第二个函数不会有“切片”问题,因为基类引用可以绑定到派生对象。因此,在这种情况下也不需要可访问的析构函数。
在 C++11 中,第一个函数将要求“A”具有可访问的“复制”或“移动”构造函数,具体取决于如何调用“h”。
根据您的 type 的复制构造函数中发生的情况A
,是的,您可能会得到不同的行为。
如其他答案中所述,按值而不是按引用传递将导致执行复制构造函数A
,这是代码采用的单独路径。如果您的类A
处理某些资源,则复制该类可能最终会将该资源的不同实例传递给函数。
实际上,这一切都取决于类的A
实际作用。
简短的回答:没有。
a
更长的答案:在您的第一个示例中,在堆栈上创建了一个完整副本。无论你用什么调用函数,都会调用 A 的复制构造函数,对于你传入的参数。当函数退出时,a
将调用析构函数。根据您的实施A
可能会非常昂贵。
A
此外,对于无法访问复制构造函数的对象、抽象类(如果是抽象的)以及如果使用派生自 的类调用,则无法调用第一个函数,函数中A
接收到的副本将被切片。
第二个功能不受这些限制。
TL;DR:你永远不应该使用第一个版本(但你的里程可能会有所不同)。
除了其他人在这里写的关于复制构建的成本a
和潜在的切片问题(如果它通过了第一种情况下的一些派生类)之外A
,这些函数具有不同的签名。
如果h
是某个类的成员函数并试图覆盖基类中的virtual
函数h
,则这两种形式将被视为不同的函数,因为它们的签名不同。这意味着第一种形式不能超载第二种形式。
如果您随后h
通过指向基类的指针调用派生类,并希望h
从派生类中调用它们,则它们的签名必须相同。否则h
将调用来自基类的。这可能会产生明显的差异。