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