Chinaunix

标题: [已解决]重载解析,为什么优先匹配非const版本? [打印本页]

作者: donet8    时间: 2012-06-04 15:02
标题: [已解决]重载解析,为什么优先匹配非const版本?
本帖最后由 donet8 于 2012-06-05 11:10 编辑

下面这个小程序,运行结果是: operator s1()

  1. #include<iostream>
  2. using namespace std;
  3. struct s;
  4. struct s1{
  5.     const s* m_s;
  6. };
  7. struct s{
  8.     operator s1()const{
  9.         cout << "operator s1() const" << endl;
  10.         return s1();
  11.     }
  12.     operator s1(){
  13.         cout << "operator s1()" << endl;
  14.         return s1();
  15.     }
  16. };
  17. void test(s1 obj){}
  18. int main(void){
  19.     test(s());
  20.     return 0;
  21. }
复制代码
如果我去掉非const的版本,那么调用的结果就是perator s1() const

这是为什么? C++标准有没有规定const和非const的那个在重载解析的过程中优先匹配?

作者: bruceteen    时间: 2012-06-04 15:22
匿名对象呀,不可作为左值,但不是const的
作者: wwwsq    时间: 2012-06-04 15:30
donet8 发表于 2012-06-04 15:02
下面这个小程序,运行结果是: operator s1()如果我去掉非const的版本,那么调用的结果就是perator s1() c ...



这种问题最好是从头就避免,而不是出现了问题再纠结。

一个类里面,就不应该出现两个同名而且同参数的函数。

如果代码写的不健康,就会面临太多难以预期的风险。对于这个问题,我的建议是不要用const去修饰函数,会有很多很多问题。这个问题只是开始。


作者: AD8018    时间: 2012-06-04 15:37
C++重载决议,搞不懂。
const带来的麻烦,和得到的好处不相上下。
作者: donet8    时间: 2012-06-04 16:01
bruceteen 发表于 2012-06-04 15:22
匿名对象呀,不可作为左值,但不是const的


不对吧,匿名对象可以作为左值啊。

string s1="abc";
string s2="xyz";
cout<<(s1+s2).c_str()<<endl;//临时对象可以作为左值,调用c_str().

作者: bruceteen    时间: 2012-06-04 16:18
我说错了,应该叫 临时对象,不叫 匿名对象
作者: dengxiayehu    时间: 2012-06-04 16:23
函数直接传递对象? 我好像没干过

我觉得应该先是非const的版本,这样在operator s1(){...}可以“尽可能”的
调用结构体s中的成员函数(不管是const还是非const属性),或是改变s中
的成员变量而不出错,胡诹的,坐等标准帝
作者: donet8    时间: 2012-06-04 16:41
本帖最后由 donet8 于 2012-06-04 16:43 编辑
bruceteen 发表于 2012-06-04 16:18
我说错了,应该叫 临时对象,不叫 匿名对象


在我的例子当中,
cout<<(s1+s2).c_str()<<endl;//临时对象可以作为左值,调用c_str().

这个s1+s2是临时对象,也是匿名对象。
没有什么不妥啊。

我的问题还是在那儿,为什么重载解析优先调没有const的版本呢?
作者: bruceteen    时间: 2012-06-04 16:57
回复 8# donet8

你的代码我看不懂呀, c_str()是个const成员,即const对象是可以调用它的
另外,即使c_str()是个non-const成员,能调用它的也不代表就是左值呀

如果 (s1+s2) = "abc" 能编译通过,那就说明(s1+s2)是左值
作者: Moon_Bird    时间: 2012-06-04 16:59
回复 3# wwwsq
有时候使用const修饰成员函数是必须得吧,
如果函数的参数为const reference传参的话,
Func(const A& a);
那么在Func内就只能调用a的const成员函数了

   
作者: wwwsq    时间: 2012-06-04 17:19
本帖最后由 wwwsq 于 2012-06-04 17:20 编辑
Moon_Bird 发表于 2012-06-04 16:59
回复 3# wwwsq
有时候使用const修饰成员函数是必须得吧,
如果函数的参数为const reference传参的话,



Func(const A& a)就不是一种好的写法。这是典型的为了解决一个问题,不得不增加N个限制,然后引入2*N个问题

等const遇到template那才叫热闹。当我看到那些稀奇古怪的规定的时候,当时就震惊了。

作为对照,可以看看java、c#、php、python的语法。


作者: donet8    时间: 2012-06-04 17:46
bruceteen 发表于 2012-06-04 16:57
回复 8# donet8

你的代码我看不懂呀, c_str()是个const成员,即const对象是可以调用它的


嗯,你说的对,能调用函数的不一定是左值,左值是有名称的,可以取地址。(s1+s2)="123";就编译不过。

作者: donet8    时间: 2012-06-04 17:50
Moon_Bird 发表于 2012-06-04 16:59
回复 3# wwwsq
有时候使用const修饰成员函数是必须得吧,
如果函数的参数为const reference传参的话,


哦,可是我觉得你的说法似乎的出的结论是应该优先匹配const版本啊。

如果优先匹配const版本的函数,那么就相当于限定了函数体里面只能调用const版本的函数,这是个更加严格的限定。
然后再匹配非const版本,限定更加宽松。
作者: shanehan    时间: 2012-06-04 17:56
wwwsq 发表于 2012-06-04 17:19
Func(const A& a)就不是一种好的写法。这是典型的为了解决一个问题,不得不增加N个限制,然后引入2*N ...


不好体现在哪里?可否具体地说说
作者: wwwsq    时间: 2012-06-04 18:10
本帖最后由 wwwsq 于 2012-06-04 18:11 编辑
shanehan 发表于 2012-06-04 17:56
不好体现在哪里?可否具体地说说



呃。。。这个帖子顶楼的问题就算一个。。。。要是不用const,不就没这个问题么?

另外,const遇到template也会出各种奇怪的问题。



作者: xue-feng    时间: 2012-06-04 22:30
本帖最后由 xue-feng 于 2012-06-04 22:37 编辑
  1. struct FOO{

  2.         int a;
  3.         void test() { a = 3; cout << "no const" << endl;  
  4. };

  5. int main()
  6. {
  7.         FOO().test();
  8.            return 0;
  9. }
复制代码
临时对象 ,不是常量。应该优先是用 non const 。 楼主的问题是 cast 操作符函数,相当于调用成员函数。不是引用临时量。引用临时量是不允许的。



作者: donet8    时间: 2012-06-05 09:20
xue-feng 发表于 2012-06-04 22:30
临时对象 ,不是常量。应该优先是用 non const 。 楼主的问题是 cast 操作符函数,相当于调用成员函数。不是 ...


可是我把test函数声明改成了用const&,传入一个非临时的变量,也还是不行啊:

  1. struct s;
  2. struct s1{
  3.     const s* m_s;
  4. };
  5. struct s2 : s1{};
  6. struct s{
  7.     operator s1()const{
  8.         cout << "operator s1() const" << endl;
  9.         return s1();
  10.     }
  11.     operator s2(){
  12.         cout << "operator s2()" << endl;
  13.         return s2();
  14.     }
  15. };
  16. void test(const s1& obj){}
  17. int main(void){
  18.     s obj;
  19.     test(obj);
  20.     return 0;
  21. }
复制代码
输出operator s2()
作者: kaisanapolun    时间: 2012-06-05 09:38
是的,优先匹配非const函数。可以换种表达:非const对象调用非const函数,而const对象调用const函数。
函数名是相同的,假设优先匹配const函数,const对象和非const对象都调用const函数,那么非const函数永远不会被调用。
作者: w_anthony    时间: 2012-06-05 09:57
wwwsq 发表于 2012-06-04 17:19
Func(const A& a)就不是一种好的写法。这是典型的为了解决一个问题,不得不增加N个限制,然后引入2*N ...


如果什么限制都没有,那么写的人是爽了,但是读的人就郁闷了,着眼点太多……

作者: 清爽之梦    时间: 2012-06-05 15:36
支持一下活动!
作者: xue-feng    时间: 2012-06-05 21:15
本帖最后由 xue-feng 于 2012-06-05 21:28 编辑

回复 17# donet8


test参数虽然是 const& ,但外面的obj不是const,这里调用的是 obj的成员函数。相当于先调用 obj.operator, 然后在将结果传给 test

如果 obj 是 const s obj;  那么  static_cast<s2>(obj); 无法cast




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2