C ++对于值和引用的语义与Java不同。首先,每种类型都有可能通过复制,引用或地址传递(但是,可以通过隐藏复制构造函数来防止通过复制传递类型)。
与Java的“按引用”传递最紧密相关的传递类型是按指针。这是三个示例:
void foo(std::string bar); // by copyvoid foo(std::string& bar); // by referencevoid foo(std::string* bar); // by address
附带说明一下,对于大于指针大小的类型,通过副本传递总是比通过引用或指针传递更昂贵。出于这个原因,您可能通常也更喜欢通过
const引用传递,这将使您无需复制即可读取对象。
void foo(const std::string& bar); // by const reference
但是,这都是棘手的问题,您需要了解Java的精妙之处,才能正确决定C
的要求。在Java中,实际上并没有通过引用传递对象:而是通过副本传递对象引用。也就是说,如果将新对象分配给参数,则父作用域的对象不会更改。在C
中,这与通过地址而不是通过引用更紧密地匹配传递的对象。这是一个重要的示例:
// Java using "object references":public static void foo(String bar){ bar = "hello world";}public static void main(String[] argv){ String bar = "goodbye world"; foo(bar); System.out.println(bar); // prints "goodbye world"}// C++ using "references":void foo(std::string& bar){ bar = "hello world";}int main(){ std::string bar = "goodbye world"; foo(bar); std::cout << bar << std::endl; // prints "hello world"}// C++ using pointers:void foo(std::string* bar){ bar = new std::string("goodbye world"); delete bar; // you don't want to leak}int main(){ std::string bar = "goodbye world"; foo(&bar); std::cout << bar << std::endl; // prints "hello world"}换句话说,当您在C 中使用引用时,实际上是在处理传递的 相同变量 。您对其所做的任何更改,甚至是分配,都将反映到父范围。(部分原因是C
如何处理赋值运算符。)使用指针,您得到的行为与Java引用的行为更紧密相关,但代价是必须通过一元运算
&符获取对象地址(请参见
foo(&bar)在我的示例中),需要使用
->运算符来访问成员,并且使用运算符重载会带来一些额外的复杂性。
另一个显着区别是,由于按引用自变量的用法在语法上与按副本自变量的用法紧密相关,因此函数应能够假定您通过引用传递的对象是有效的。即使通常可以传递对的引用
NULL,也强烈建议不要这样做,因为这样做的唯一方法是取消引用
NULL,这具有不确定的行为。因此,如果您需要能够
NULL作为参数传递,则更希望通过地址传递参数,而不是通过引用传递参数。
大多数情况下,当您要修改函数中的参数时,您希望通过引用而不是地址进行传递,因为它更“ C ++友好”(除非您需要该
NULL值),即使它不完全像Java。



