在c++中,&代表引用传递,跟指针的作用是一致的,只不过语法上做了一点点修改。
c++中函数参数如果是类对象一般使用&来修饰,从而避免不必要的构造和析构。
例如
class A{ };
void func(A&) { }
使用A&可以避免调用 A(A&) 来创建临时对象和 ~A() 来销毁临时对象。
看下面代码
void func(string& ) { }
int main() {
func("asdfasdf");
}
如果直接编译的话会出现 no matching function for call to 'myclass::myclass(const char [9])'
的错误信息。
如果把函数参数改为 const string&
就可以编译通过。
技巧:重载函数
void func(string& ) { cout << "1" << endl; } // func函数1
void func(const string& ) { cout << "2" << endl; } // func函数2
int main() {
string s("abcd");
func(s); //调用func函数1
func("asdfasdf"); //调用func函数2
}
运行结果分别输出1,2
这样重载函数的好处是外部对象调用时不需要构造string对象,调用起来比较的方便。
如何理解
编写如下测试代码
class A{
public:
A() { cout << "A()" << endl; }
A(const char*) { cout << "A(const char*)" << endl; }
A(A&) { cout << "A(A&)" << endl; }
};
void func(A&) { cout << "call func(A&)" << endl; }
void func(const A&) { cout << "call func(const A&)" << endl;}
int main() {
A a("abcdef"); // 调用A(const char*)
func(a); //调用func函数1
cout << endl;
func("asdfasdf"); //调用func函数2
}
运行结果如下
理解:
第一行输出A(const char*)
为A a(“abcdef”) 调用构造函数;
第二行输出call func(A&) 表示调用func过程没有任何拷贝过程;
第四行输出 A(const char*)
是关键点,代表这个字符串对象先调用A(const char*) 构造函数然后在把生成的对象作为const引用传递给参数。函数参数必须是const才能被接受,如果你在func函数里面需要进行非const的操作,则首先需要一个进行一个 const_cast<A&> 转型 (我只知道必须加const,不知道为什么要加const,有这方面详细的文档的哥们请留言)
简而言之:函数参数是const的引用具有调用构造函数复制新对象的能力(但不是一定会复制新对象)
对继承的影响
#include <iostream>
class Base {
public:
//const Base&如果改为 Base& 编译将不通过
friend std::ostream&operator << (std::ostream& ,const Base&) { }
};
class A:public Base { };
int main() {
std::cout << A(); // 调用Base的operator << 方法,需要对A对象转型,只能转为const Base&
}
简而言之:加了const可以转为基类引用,而不需要复制新的对象
一个复杂的例子
这是我编写的一份关于继承和重载<< 的代码,代码虽然短,内容相当多,需要好好理解。
#include <iostream>
#include <string>
using namespace std;
class Base {
string data;
public:
virtual void setdata(string& data) { this->data = data; }
virtual void setdata(const string& data){ this->data = data; }
friend ostream&operator << (ostream& os,const Base& b) { // 如果把const删除则导致输出A对象失败,可以删除试下
os << b.data;
return os;
}
};
class A:public Base {
public:
virtual void func() { }
A() { }
A(string& data) { setdata(data); }
A(const char* data) { setdata(data); }
A(const string& data) { setdata(const_cast<string&>(data)); } // 使用了const_cast 对const对象转型
};
void func(const A& s) {
cout << s << endl; // 匹配到 ostream&operator << (ostream& os,const Base& b); 函数 ;
}
int main() {
cout << A("1234") << endl; //A("1234")调用了构造函数A(const string& data); 使用了上面的技巧
func("5678"); // "5678"先调用A(const char*data) 构造,然后setdata(data)在调用 void setdata(const string& data)
}