最近在做面向对象的研讨作业,在写代码时遇到一些令我抓狂的问题,在经过漫长的检查翻书搜索后总算都解决了。
下面把问题提取出来,做个记录。
比如说在类内定义了个运算符重载:
char & operator[](size_t x);
这个是为了能把返回值即当右值又当左值。但是,如果要在加const的参数上使用,则是不允许的:
void test(const (类名) & a){a[0];} // error
原因是当参数加const 后则不允许使用任何可能修改对象的功能,返回引用也不允许,即使你没有写出修改数据的语句。
解决方案是再写个函数重载:
1 char & operator[](size_t x); 2 const char & operator[](size_t x) const; //这里在后面也要加const 否者无法区别两函数的类型(不能用返回值区别)
这样就解决问题了!
==================================分割线===================================
还是更运算重载有关,看如下代码:
1 class mystring 2 { 3 public: 4 mystring() {}; 5 mystring(const mystring & a){} 6 mystring& operator=(mystring &a){return *this;} 7 mystring operator+(const mystring &a) 8 { 9 return a; 10 } 11 }; 12 int main() 13 { 14 mystring a,b; 15 a+b; //OK! 16 a=a+b; //error 17 }
这段代码是不能编译的(在GCC下不行,可能在VC下可以),原因出在=号重载上。
由于+号返回的是个临时变量,它不能当左值 ,而等号的参数是个引用,可能可以被修改,所以非法。解决办法就是 参数声明为 const。
看来GCC的编译器语法检查的更严点,VC的包容性更好。
通过前两个例子,可以看出const 的威力所在,所以写代码时,能加const就加 const !
==================================分割线===================================
下面是个关于构造函数和 explicit 的问题:
1 class mystring 2 { 3 public: 4 explicit mystring(){} 5 explicit mystring(const mystring & a){} 6 mystring operator+(const mystring &a) 7 { 8 return a; 9 } 10 };
这段代码无法编译。
问题是如果把第二个构造函数的explicit 禁止隐式转换 标记删了,编译就会正确,否则错误。
出错在+号重载里的 "return a;" 提示 no matching
function for call to 'mystring::mystring(const mystring&)'
正常情况下 return a 调用的是 复制构造函数 ,但我已经写了而且参数类型对应。为什么还会错呢?
在return a的时候,编译器需要“偷偷地”地调用拷贝构造函数构造一个临时对象,而explicit关键字阻止了这种行为,所以编译出错。
加explicit的构造函数必须在程序里显式调用,连编译器自动调用的都不行。所以看来拷贝构造函数不能加explicit 。