首先解释一下这个标题的意思吧,就是使用引用传参来替换传值传参,因为传值传参相比传引用来说有着太多的不方便,下面我来详细说明一下理由
1.理由1.使用by value会产生很多麻烦的过程(比如调用拷贝构造函数等一系列不必要的函数),看如下代码
int n = 0;
class String
{
public:
String()
{
n++;
cout << "String::构造函数 n="<<n << endl;
}
String(const String& s)
{
n++;
cout << "String::拷贝构造函数 n=" << n << endl;
}
virtual ~String()
{
n++;
cout << "String::析构函数 n=" << n << endl;
}
};
class Base
{
public:
Base()
{
n++;
cout << "Base::构造函数 n=" << n << endl;
}
Base(const Base& s)
:name(s.name)
,address(s.address)
{
n++;
cout << "Base::拷贝构造函数 n=" << n << endl;
}
virtual ~Base()
{
n++;
cout << "Base::析构函数 n=" << n << endl;
}
private:
String name;
String address;
};
class Dervice :public Base
{
public:
Dervice()
{
n++;
cout << "Dervice::构造函数 n=" << n << endl;
}
Dervice(const Dervice& s) :Base(s), Derviceddress(s.Derviceddress), Dervicename(s.Dervicename)
{
n++;
cout << "Dervice::拷贝构造函数 n=" << n << endl;
}
virtual ~Dervice()
{
n++;
cout << "Dervice::析构函数 n=" << n << endl;
}
private:
String Dervicename;
String Derviceddress;
};
bool validata(Dervice s)
{
return 0;
}
void test()
{
Dervice ww;
cout << "****************************************" << endl;
bool n = validata(ww);
}
int main()
{
test();
system("pause");
return 0;
}
这是一个by-value的方式传参的函数的调用validata函数。
所以在这里首先1.调用Dervice的拷贝构造函数以ww为蓝本将s初始化,同样的在validata函数结束以后s会被销毁,调用Dervice的析构函数。当然这只是大概的基本调用,事情往往没那么简单,就上面的这个例子来看,因为每个类的成员也都是一个string 类型的。
所以上面完整的调用函数是1.调用Dervice的拷贝构造函数,2.调用Base的拷贝构造函数,3.调用Base中的第一个string的拷贝构造函数,4.调用Base中的第二个string的拷贝构造函数,5.调用Dervice的第一个string的拷贝构造函数,6,调用Dervice的第二个string的拷贝构造函数。当validata调用结束以后销毁s的时候又分别调用对应的析构函数。
这样看来传值是不是非常的恶心中间要调用这么多次函数,效率相对来说肯定是比较低的,
所以如果我们以引用的方式来传参,那么将会简单的很多
bool validata(Dervice &s)
{
return 0;
}
void test()
{
Dervice ww;
cout << "****************************************" << endl;
bool n = validata(ww);
}
但是在这里提醒一点函数的形参应该加上const修饰
bool validata(const Dervice &s)
{
return 0;
}
上面的演示我没有加,为什么要加这个const,因为之前以值传递的方式传递过去的是ww的副本,函数内部不会对main中的ww做任何改变,改变的只是ww在validata中的副本,但是现在传递形式是引用传递,如果不声明为const的话,在validata中更改的话相当于更改了main中的ww.
这为什么要用引用而不用值传递的理由1,下面我来阐述理由二
2.使用引用传递会避免对象切割问题
首先对象切割是什么呢?
解释:我用代码来说明吧
class Base
{
public:
virtual void fun()
{
cout << "Base:;fun" << endl;
}
Base()
{}
Base(Base & s)
{
cout << "Base::拷贝构造函数" << endl;
}
};
class Dervice :public Base
{
public:
virtual void fun()
{
cout << "Dervice:;fun" << endl;
}
Dervice()
{}
Dervice(Dervice &s) :Base(s)
{
cout << "Base::拷贝构造函数" << endl;
}
};
void test(Dervice s)
{
s.fun();
}
int main()
{
Dervice ww;
test(ww);
system("pause");
return 0;
}
上述就是一个对象切割的例子.
一个在继承中,当一个Dervice对象以传值的方式传递并且接受他的为形参为Base类型的话,那么这个时候Base的拷贝构造函数就会被调用,而不是Dervice的拷贝构造函数被调用,这样就会造成Dervice对象的特性全部被切割掉了,仅仅留下一个Base对象的特性,这就是对象切割,所以在Test中调用fun的话,只会调用基类对象的函数。而绝不会调用派生类的函数。
这个时候使用引用传递的方式就可以解决这个问题。
void test(Base& s)
{
s.fun();
}
int main()
{
Dervice ww;
test(ww);
system("pause");
return 0;
}
现在传进来什么类型,w就表现哪种类型。
这就解决了对象切割的问题!
最后要说的就是:
当对象为内置类型或者STL的迭代器和函数对象,可以考虑使用传值的方式,否则的话尽量采用引用传值的方式!