C++ 何时使用引用或指针传递参数
在C++中,使用引用传递变量有以下原因:
1) 改变调用函数的局部变量: 引用(或指针)允许被调用函数修改调用函数的局部变量。考虑以下示例程序,在这个程序中,fun()可以改变main函数的局部变量x。
C++代码:
#include
using namespace std;
void fun(int& x) { x = 20; }
int main()
{
int x = 10;
fun(x);
cout << "New value of x is " << x;
return 0;
}
输出:
New value of x is 20
2)当传递大型参数时: 当传递大型参数时,通过引用(或指针)传递更高效,因为只传递地址,而不是整个对象。考虑以下Employee类和printEmpDetails()函数,该函数打印Employee的详细信息。
C代码
class Employee {
private:
string name;
string desig;
// More attributes and operations
};
void printEmpDetails(Employee emp)
{
cout << emp.getName();
cout << emp.getDesig();
// Print more attributes
}
上面的代码问题是: 每次调用 printEmpDetails () 都会构造一个新的 Employee 对象,这涉及创建所有数据成员的副本。所以更好的实现方式是将 Employee 作为引用传递。
void printEmpDetails(const Employee& emp)
{
cout << emp.getName();
cout << emp.getDesig();
// Print more attributes
}
这仅适用于struct和class变量,因为int、char等基本类型没有效率优势。
3) 避免对象切割: 如果我们将一个子类对象传递给一个期望超类对象的函数,如果通过值传递,传递的对象将被切割。考虑下面的程序,它会打印出”This is Pet Class”。
C代码
#include
using namespace std;
class Pet {
public:
virtual string getDescription() const
{
return "This is Pet class";
}
};
class Dog : public Pet {
public:
virtual string getDescription() const
{
return "This is Dog class";
}
};
void describe(Pet p)
{ // Slices the derived class object
cout << p.getDescription() << '\n';
}
int main()
{
Dog d;
describe(d);
return 0;
}
输出:
This is Pet Class
在上面的程序中,当我们使用引用传递时,它正确地打印出“ This is Dog Class”。请参见下面修改后的程序。
C++代码
#include
using namespace std;
class Pet {
public:
virtual string getDescription() const
{
return "This is Pet class";
}
};
class Dog : public Pet {
public:
virtual string getDescription() const
{
return "This is Dog class";
}
};
void describe(const Pet& p)
{ // Doesn't slice the derived class object.
cout << p.getDescription() << '\n';
}
int main()
{
Dog d;
describe(d);
return 0;
}
输出:
This is Dog Class
这对于int、char等基本数据类型也不正确。
4) 在函数中获得运行时多态性: 通过将对象作为引用(或指针)传递给函数,我们可以使其具有多态性。示例,在下面的程序中,print()接收到一个基类对象的引用。如果传递了一个基类对象,函数print()调用基类函数show(),如果传递了一个派生类对象,函数show()被调用。
C++代码
#include
using namespace std;
class base {
public:
virtual void show()
{ // Note the virtual keyword here
cout << "In base\n";
}
};
class derived : public base {
public:
void show () { cout << "In derived\n"; }
};
// Since we pass b as reference, we achieve run time
// polymorphism here.
void print (base& b) { b.show(); }
int main(void)
{
base b;
derived d;
print (b);
print (d);
return 0;
}
输出:
In base
In derived
- 指针具有值,并且因为C++中默认按值传递函数参数,所以当使用指针时,指针的副本被传递给函数。
结论
如果参数很大(比如一个包含多个字符串的列表),最好使用按引用传递,以避免移动整个字符串。按引用传递实际上只传递参数的地址,而不是参数本身。