如何将对象传递给C ++中的函数?
我是C ++编程新手,但我有Java经验。 我需要指导如何将对象传递给C ++中的函数。
我是否需要传递指针,引用或非指针和非引用值? 我记得在Java中没有这样的问题,因为我们只传递了保存对象引用的变量。
如果你还可以解释在哪里使用这些选项,那将是非常好的。
经验法则C ++ 11:
按价值传递,除了何时
const
引用传递 , const
左值引用传递 , const
引用传递。) 几乎从不建议通过指针。 可选参数最好用boost::optional
表示,并且通过引用可以很好boost::optional
别名。
即使对于复杂对象,C ++ 11的移动语义也使得传值和返回值更具吸引力。
C ++ 03的经验法则:
通过const
引用传递参数,除了when
const
NULL
/ 0
/ nullptr
; 应用先前的规则来确定是否应该传递一个指向const
参数的指针 (在这里,“按值传递”称为“通过复制”,因为按值传递总是在C ++中创建一个副本03)
还有更多,但这些初学者的规则会让你走得很远。
C ++和Java中的调用约定存在一些差异。 在C ++中,技术上讲只有两种约定:传值和传递引用,一些文献包括第三种传递指针约定(实际上是指针类型的传值)。 最重要的是,您可以将常量添加到参数的类型中,从而增强语义。
通过参考传递
按引用传递意味着函数将从概念上接收对象实例,而不是其副本。 该引用在概念上是在调用上下文中使用的对象的别名,并且不能为空。 在函数内执行的所有操作都适用于函数外部的对象。 此惯例在Java或C中不可用
按值传递(并传递指针)
编译器将在调用上下文中生成对象的副本,并在该函数内使用该副本。 在函数内部执行的所有操作都是针对副本完成的,而不是外部元素。 这是Java中原始类型的约定。
它的一个特殊版本是将一个指针(对象的地址)传递给一个函数。 该函数接收指针,并且将应用于指针本身的所有操作应用于副本(指针),另一方面,应用于解除引用的指针的操作将应用于该存储器位置处的对象实例,所以函数可能有副作用。 使用指向该对象的指针传值的效果将允许内部函数修改外部值,就像通过引用传递一样,并且还将允许可选值(传递空指针)。
这是C语言在函数需要修改外部变量时使用的约定,以及Java中引用类型使用的约定:复制引用,但引用的对象相同:对引用/指针的更改不可见该函数,但改变了指向的内存。
将等式添加到等式中
在C ++中,可以在定义变量,指针和不同级别的引用时为对象分配常量。 你可以声明一个变量为常量,你可以声明一个常量实例的引用,并且你可以定义所有指向常量对象的指针,指向可变对象的常量指针和指向常量元素的常量指针。 相反,在Java中,您只能定义一个常量级别(final关键字):变量的类型(基本类型的实例,引用类型的引用),但不能定义对不可变元素的引用(除非类本身是不可变的)。
这在C ++调用约定中被广泛使用。 当对象很小时,可以按值传递对象。 编译器将生成一个副本,但该副本不是一个昂贵的操作。 对于任何其他类型,如果函数不会更改对象,则可以将引用传递给该类型的常量实例(通常称为常量引用)。 这不会复制该对象,而是将其传递给该函数。 但是同时编译器会保证函数内部的对象没有被改变。
经验法则
这是一些基本的规则:
这些规则还有一些小的偏差,第一个是处理对象的所有权。 当一个对象用new动态分配时,它必须用delete(或其[]版本)解除分配。 负责销毁对象的对象或函数被认为是资源的所有者。 当在一段代码中创建一个动态分配的对象时,所有权被转移到另一个元素上时,通常使用传递指针语义来完成,或者如果可能的话使用智能指针来完成。
边注
坚持C ++和Java引用之间差异的重要性是非常重要的。 在C ++中,引用在概念上是对象的实例,而不是它的访问器。 最简单的例子是实现交换功能:
// C++
class Type; // defined somewhere before, with the appropriate operations
void swap( Type & a, Type & b ) {
Type tmp = a;
a = b;
b = tmp;
}
int main() {
Type a, b;
Type old_a = a, old_b = b;
swap( a, b );
assert( a == old_b );
assert( b == old_a );
}
上面的交换函数通过使用引用来更改它的参数。 Java中最接近的代码:
public class C {
// ...
public static void swap( C a, C b ) {
C tmp = a;
a = b;
b = tmp;
}
public static void main( String args[] ) {
C a = new C();
C b = new C();
C old_a = a;
C old_b = b;
swap( a, b );
// a and b remain unchanged a==old_a, and b==old_b
}
}
Java版本的代码将在内部修改引用的副本,但不会从外部修改实际对象。 Java引用是没有指针算术的C指针,它被值传递给函数。
有几种情况需要考虑。
参数修改(“输出”和“输入/输出”参数)
void modifies(T ¶m);
// vs
void modifies(T *param);
这种情况主要是关于风格的:你想让代码看起来像调用(obj)还是调用(&obj)? 但是,有两点差异很重要:下面是可选的情况,并且您希望在重载操作符时使用引用。
...和可选的
void modifies(T *param=0); // default value optional, too
// vs
void modifies();
void modifies(T ¶m);
参数未修改
void uses(T const ¶m);
// vs
void uses(T param);
这是一个有趣的案例。 经验法则是“便宜复制”类型通过值传递 - 这些通常是小类型(但不总是) - 而其他类型则通过const ref传递。 然而,如果你需要在你的函数中创建一个副本,你应该传递值。 (是的,这暴露了一些实现细节。C'est le C ++。)
...和可选的
void uses(T const *param=0); // default value optional, too
// vs
void uses();
void uses(T const ¶m); // or optional(T param)
这里所有情况之间的差别最小,所以选择哪一个让你的生活变得最简单。
按值进行Const是一个实现细节
void f(T);
void f(T const);
这些声明实际上是完全相同的功能! 当传值时,const纯粹是一个实现细节。 试试看:
void f(int);
void f(int const) { /* implements above function, not an overload */ }
typedef void NC(int); // typedefing function types
typedef void C(int const);
NC *nc = &f; // nc is a function pointer
C *c = nc; // C and NC are identical types
链接地址: http://www.djcxy.com/p/3527.html