先来看一看我写的string容器(包含了基本的构造,析构,赋值,拷贝)。
class String {
public:
//构造
/*explicit*/ String(const char* arr = "") {
assert(arr);//判别不会传入空指针
cout << "String(const char* arr="")" << endl;
_str = new char[strlen(arr) + 1];
strcpy(_str, arr);
}
/*拷贝构造*/
String(const String& arr)
:_str(nullptr)
{
cout << "String (const String& arr)" << endl;
_str = new char[arr.size() + 1];
strcpy(_str, arr._str);
}
String& operator=( String a) {
cout << "String&operator=(String a)" << endl;
swap(_str, a._str);
return *this;
}
~String() {
if (_str) {
delete _str;
_str = nullptr;
}
}
int size()const {
return strlen(_str);
}
private:
char* _str;
};
在我测试这段代码是我先定义const String A和String B,然后把A赋值给B。
显然B=A用到了赋值重载。
const String A("abcd");
String B;
B = A;
但是令我疑惑的是并没有报错,这是为什么?我写的赋值重载函数的参数明明是String类型,而我传入的却是Const String,显然String并不能接受const String的参数。但是编译,运行都没有报错,这是为什么?
幸运的是我在函数里加入了显示被调用的语句->cout << "String&operator=(String a)" << endl;等。这是运行的结果:
A先被构造,然后是B被构造,很合理。接着就是拷贝构造,关键就在拷贝构造上!想一下,为什么要调用拷贝构造呢?
对,没错,我们的赋值重载是传值函数,String& operator=( String a)传入的是A的一份拷贝,那必然要调用拷贝函数。
这时我们再来看看拷贝函数 String(const String& arr) 它的参数是const 引用。没错,重点就在于const 上,我们传入的A是const类型,然后被拷贝函数接受,拷贝函数的参数也是const类型,所以会被拷贝函数接收。
拷贝函数创建了一个Stirng对象,这个对象是没有被const修饰,因而可以被赋值重载函数接收。
所以!这就是为什么赋值重载能够接受const类型对象的传参了,因为是拷贝构造函数先接收的!
因而不会出现权限被放大的问题。