C++ 是按值还是按引用传递对象?

问题描述 投票:0回答:6

一个简单的问题,我在这里找不到答案。

我的理解是,在调用期间将参数传递给函数时,例如

void myFunction(type myVariable)
{
}

void main()
{
    myFunction(myVariable);
}

对于简单数据类型,如

int
float
等,函数按值调用。

但是如果

myVariable
是一个数组,则仅传递起始地址(即使我们的函数是按值调用函数)。

如果

myVariable
是一个对象,也仅传递该对象的地址,而不是创建副本并传递它。

回到问题。 C++ 是通过引用还是通过值传递对象?

c++ pass-by-reference pass-by-value pass-by-pointer
6个回答
78
投票

参数按值传递,除非函数签名另有指定:

  • void foo(type arg)
    中,
    arg
    是按值传递的,无论
    type
    是简单类型、指针类型还是类类型,
  • void foo(type& arg)
    中,
    arg
    是通过引用传递的。

对于数组,传递的值是指向数组第一个元素的指针。如果您在编译时知道数组的大小,也可以通过引用传递数组:

void foo(type (&arg)[10])


30
投票

C++ 总是给你选择:所有类型

T
(数组除外,见下文)都可以通过将参数类型设置为
T
来按值传递,并通过将参数类型设置为
T &
、引用来按引用传递-到-
T

当参数类型没有显式注释为引用时(

type &myVariable
),无论具体类型如何,它都始终按值传递。也适用于用户定义的类型(这就是复制构造函数的用途)。同样对于指针,即使复制指针并不会复制所指向的内容。

数组有点复杂。数组不能按值传递,int arr[]之类的

参数
类型实际上只是
int *arr
的不同语法。这不是传递给从数组生成指针的函数的行为,几乎所有可能的操作(仅不包括像
sizeof
这样的少数操作)都会这样做。一个 can 传递对数组的引用,但这明确注释为引用:
int (&myArray)[100]
(注意&符号)。


9
投票

C++ 使按值传递和按引用传递范例成为可能。

您可以在下面找到两个示例用法。

http://www.learncpp.com/cpp-tutorial/72-passing-arguments-by-value/

http://www.learncpp.com/cpp-tutorial/73-passing-arguments-by-reference/

数组是特殊的构造,当您将数组作为参数传递时,指向第一个元素地址的指针将作为数组中元素类型的值传递。

当你传递指针作为参数时,你实际上自己实现了引用传递范式,就像在C中一样。因为当你修改指定地址中的数据时,你实际上修改了调用函数中的对象。


0
投票

在 C++ 中,声明为类、结构或联合的类型被视为“类类型”。这些是按值传递的,或者您可以说使用复制构造函数的副本传递给函数。当我们实现二叉树时,这一点非常明显,其中作用于二叉树的递归函数中几乎总是有 Node * 类型的参数。这是为了方便对该节点的修改。如果节点按原样传递(即不是指针类型),则对节点的修改将针对本地副本。即使在向量的情况下,在将向量的副本传递给函数时,为了避免我们使用引用 &。


0
投票

上面已经有非常丰富的答案了。下面我只是分享一个测试用例,希望对未来的读者有所帮助:

#include <iomanip> 
#include <iostream>
#include <vector>

struct MyStruct
{
    MyStruct(int val = 1) :dim(val) { c = new double[dim]; }
    int a = 0;
    double b[3] = { 1,2,3 };
    double* c;
    std::vector<int> vec_i;
    std::vector<double> vec_d;
    int get_dim() { return dim; }
private:
    int dim;
};

static void test_w_val(MyStruct ms, double arr[5])
{
    for (int i = 0; i < 5; i++)
        arr[i] = 2 * i + 1;

    ms.a = 10;
    ms.b[0] = 100;
    ms.b[1] = 200;
    ms.b[2] = 300;

    for (int i = 0; i < ms.get_dim(); i++)
        ms.c[i] = 1000 + i;

    ms.vec_d.push_back(1e4);
    ms.vec_d.push_back(2e4);

    ms.vec_i.push_back(50);
    ms.vec_i.push_back(60);
}

static void test_w_ref(MyStruct& ms, double (&arr)[5])
{
    for (int i = 0; i < 5; i++)
        arr[i] = 2 * i + 1;

    ms.a = 10;
    ms.b[0] = 100;
    ms.b[1] = 200;
    ms.b[2] = 300;

    for (int i = 0; i < ms.get_dim(); i++)
        ms.c[i] = 1000 + i;

    ms.vec_d.push_back(1e4);
    ms.vec_d.push_back(2e4);

    ms.vec_i.push_back(50);
    ms.vec_i.push_back(60);
}

int main()
{
    using std::cout;
    using std::endl;

    double my_arr1[5] = { 1.,2.,3.,4.,5. }, my_arr2[5] = { 1.,2.,3.,4.,5. };
    MyStruct s1(2), s2(2);

#pragma region Prior to calls
    cout << "Before calling functions\n";
    cout << "Array:\n";
    for (int i = 0; i < 5; i++)
        cout << my_arr1[i] << " ";
    cout << endl;

    cout << "Struct:\n";
    cout << "dim: " << s1.get_dim() << endl;

    cout << "a: " << s1.a << "\n";

    cout << "b: ";
    for (int i = 0; i < 3; i++)
        cout << s1.b[i] << " ";
    cout << endl;

    cout << "c: ";
    for (int i = 0; i < s1.get_dim(); i++)
        cout << s1.c[i] << " ";
    cout << endl;

    cout << "vec_i: ";
    for (int i = 0; i < s1.vec_i.size(); i++)
        cout << s1.vec_i[i] << " ";
    cout << endl;

    cout << "vec_d: ";
    for (int i = 0; i < s1.vec_d.size(); i++)
        cout << s1.vec_d[i] << " ";
    cout << endl;
#pragma endregion

#pragma region val.
    test_w_val(s1, my_arr1);
    cout << "\nTest with Val.\n";
    cout << "Array:\n";
    for (int i = 0; i < 5; i++)
        cout << my_arr1[i] << " ";
    cout << endl;

    cout << "Struct:\n";
    cout << "dim: " << s1.get_dim() << endl;

    cout << "a: " << s1.a << "\n";

    cout << "b: ";
    for (int i = 0; i < 3; i++)
        cout << s1.b[i] << " ";
    cout << endl;

    cout << "c: ";
    for (int i = 0; i < s1.get_dim(); i++)
        cout << s1.c[i] << " ";
    cout << endl;

    cout << "vec_i: ";
    for (int i = 0; i < s1.vec_i.size(); i++)
        cout << s1.vec_i[i] << " ";
    cout << endl;

    cout << "vec_d: ";
    for (int i = 0; i < s1.vec_d.size(); i++)
        cout << s1.vec_d[i] << " ";
    cout << endl;
#pragma endregion

#pragma region Ref
    test_w_ref(s2, my_arr2);
    cout << "\nTest with Ref.\n";
    cout << "Array:\n";
    for (int i = 0; i < 5; i++)
        cout << my_arr2[i] << " ";
    cout << endl;

    cout << "Struct:\n";
    cout << "dim: " << s2.get_dim() << endl;

    cout << "a: " << s2.a << "\n";

    cout << "b: ";
    for (int i = 0; i < 3; i++)
        cout << s2.b[i] << " ";
    cout << endl;

    cout << "c: ";
    for (int i = 0; i < s2.get_dim(); i++)
        cout << s2.c[i] << " ";
    cout << endl;

    cout << "vec_i: ";
    for (int i = 0; i < s2.vec_i.size(); i++)
        cout << s2.vec_i[i] << " ";
    cout << endl;

    cout << "vec_d: ";
    for (int i = 0; i < s2.vec_d.size(); i++)
        cout << s2.vec_d[i] << " ";
    cout << endl;
#pragma endregion

    return 0;
}

这是输出:

Before calling functions
Array:
1 2 3 4 5
Struct:
dim: 2
a: 0
b: 1 2 3
c: -6.27744e+66 -6.27744e+66
vec_i:
vec_d:

Test with Val.
Array:
1 3 5 7 9
Struct:
dim: 2
a: 0
b: 1 2 3
c: 1000 1001
vec_i:
vec_d:

Test with Ref.
Array:
1 3 5 7 9
Struct:
dim: 2
a: 10
b: 100 200 300
c: 1000 1001
vec_i: 50 60
vec_d: 10000 20000

最后来自这个

将数组传递给函数的机制(a 指向数组第一个元素的指针被传递给函数) 功能类似于按引用传递

也就是说,即使您没有显式传递对它的引用,您在函数内对数组所做的任何更改都会改变原始数组。

如果您想将数组传递给函数并保护它免受突变,您可以手动创建它的副本并将副本传递给函数。或者,您可以使用包装数组的容器,例如

std::array
std::vector
[来源]


-6
投票

C++ 按值传递不是指针 (int*) 或引用 (int&) 的参数。您不能修改被调用函数中调用块的 var。数组是指针。

© www.soinside.com 2019 - 2024. All rights reserved.