鱼C论坛

 找回密码
 立即注册
查看: 3029|回复: 11

[已解决]函数形参的顶层const和底层const

[复制链接]
发表于 2019-1-8 17:26:58 | 显示全部楼层 |阅读模式
10鱼币
如图  
当形参为顶层const的时候,   两种函数是相同的;
当形参为底层const的时候,   两种函数是不同的;
大写的 why!!!???
最佳答案
2019-1-8 17:26:59
竟无语凝噎 发表于 2019-1-9 19:46
如果按照您说的这样理解的话;
因为const 的引用是一个常量,是一个右值。
但是

Record lookup(Phone);
Record lookup(const Phone);
因为这俩声明的参数列表都是形参,当用实参给形参初始化的时候,编译器会忽略掉形参前面的const,因此这俩函数经过编译器的名称修饰之后的函数名是一样的。但若参数列表里是引用或指针,那么编译器在做名称修饰的时候就不会忽略掉const。
尽管两者经过修饰后函数名一样,但编译器在编译阶段会帮你检查你传入的参数是否符合左值或右值定义。
只能说人家编译器厂商就是这么去实现这个语法的,咱只能记得不要跳进这个坑就好。也许不久后新标准就支持这两种声明共存了。
图1.png
图2.png
图3.png

最佳答案

查看完整内容

Record lookup(Phone); Record lookup(const Phone); 因为这俩声明的参数列表都是形参,当用实参给形参初始化的时候,编译器会忽略掉形参前面的const,因此这俩函数经过编译器的名称修饰之后的函数名是一样的。但若参数列表里是引用或指针,那么编译器在做名称修饰的时候就不会忽略掉const。 尽管两者经过修饰后函数名一样,但编译器在编译阶段会帮你检查你传入的参数是否符合左值或右值定义。 只能说人家编译器厂商就是这么 ...
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-1-8 17:26:59 | 显示全部楼层    本楼为最佳答案   
竟无语凝噎 发表于 2019-1-9 19:46
如果按照您说的这样理解的话;
因为const 的引用是一个常量,是一个右值。
但是

Record lookup(Phone);
Record lookup(const Phone);
因为这俩声明的参数列表都是形参,当用实参给形参初始化的时候,编译器会忽略掉形参前面的const,因此这俩函数经过编译器的名称修饰之后的函数名是一样的。但若参数列表里是引用或指针,那么编译器在做名称修饰的时候就不会忽略掉const。
尽管两者经过修饰后函数名一样,但编译器在编译阶段会帮你检查你传入的参数是否符合左值或右值定义。
只能说人家编译器厂商就是这么去实现这个语法的,咱只能记得不要跳进这个坑就好。也许不久后新标准就支持这两种声明共存了。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-1-8 21:52:12 | 显示全部楼层
建议你换一本书,我认为这本书不好
我学了这么长时间的C++,还没有听说过顶层const和底层const,而且我也看不懂这本书想要说什么
推荐《C++ Primer Plus第6版中文版》
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-1-8 22:14:41 | 显示全部楼层
好吧,这本书是《C++ primer》吗?
听说有好多人推荐这本书,我没看过这本书,那只能说是这本书在这部分讲的不好吧,其他部分我不知道,反正这一部分讲的不好^_^
换一本书吧
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-1-8 22:55:15 | 显示全部楼层
本帖最后由 rencaixiaomeng 于 2019-1-8 23:05 编辑

这个问题和之前很类似啊,你到底想问什么
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2019-1-9 09:05:32 | 显示全部楼层
人造人 发表于 2019-1-8 22:14
好吧,这本书是《C++ primer》吗?
听说有好多人推荐这本书,我没看过这本书,那只能说是这本书在这部分讲 ...

是C++primer
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2019-1-9 11:26:06 | 显示全部楼层
rencaixiaomeng 发表于 2019-1-8 22:55
这个问题和之前很类似啊,你到底想问什么

是这样 我可能说的不是很清晰 :
图2和图3中
Record lookup(Phone);
Record lookup(const Phone);
这两个是重复声明(这个可以理解: 因为在传参的时候如果只是Phone类型 而不是const Phone类型,这两个函数都可以被调用,有了二义性,所以是重复声明)。

Record lookup(Phone*);
Record lookup( Phone * const);
这两个同样是重复声明(原理如上面的解释)。

也即传入的const参数如果影响的是传入的参数本身(顶层const),那么就可能产生二义性。

Record lookup(Account *);
Record lookup(const Account *);
这个我的理解是  传入的参数是一根指针,都是指针变量而非常量,const 影响的是指针指向的数值(加const的表示指针指向的是常量,不加表示指向的是变量)。 那么在这里我的理解是对于传入的指针变量,两个函数是没有区分性的,也即在调用的时候会产生二义性。 所以个人认为这里不是重载

Record lookup(Account &);
Record lookup(const Account &);
这两个我的理解与上面的指针传入相同 也会产生二义性(这里的引用传递个人认为与指针传递相同,其实在内部实现的时候都是传入的指针,只是表示形式不同)。所以个人认为这里不是重载

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-1-9 16:05:17 | 显示全部楼层
本帖最后由 luvmdy 于 2019-1-9 16:44 编辑

你的问题和这个应该和这个有异曲同工之处“initial value of reference to non-const must be an lvalue”。
以下述为例:
Record lookup(Account&);
Record lookup(const Account&);
首先,如果你在形参列表里放的是左值,那很好,两种声明都不会报错。但,如果你放一个右值在形参列表里,那么第一种声明就会报错,错误信息就是第一句话。因此第二种声明是特别针对形参列表放右值的。
或许你有点疑惑有些右值不是可以被赋值吗?对,是可以被赋值,但这种赋值之后的结果是不可预测的,编译和链接能通过,但结果不对。你应该时刻记住右值只能出现在赋值操作符的右边,那么,你的形参列表里就应该加上const
Capture.PNG

举个栗子:
class Keyboard
{
    enum keys
    {
        W=0x01;
        S=0x02;
    }
    bool IsKeyDown(keys& key){//实现不重要...}
    bool IsKeyDownMod(const keys& key){//实现不重要...}
};
int main(void)
{
    Keyboard keyboard;
    keyboard.IskeyDown(Keyboard::W);        //报错:initial value of reference to non-const must be an lvalue
    keyboard.IskeyDowModn(Keyboard::W);                //不报错,因为Keyboard::W是右值
}
我自己封装的键盘类有七八百行代码,以上代码是从我的项目中精简出来的,但你的这个问题也确实是我在封装自己的键盘类中遇到的。因此,你可以参考这个栗子去理解为啥这两种声明不一样。
再次声明:这个精简的代码我没有测试能不能运行,至少还原回七八百行状态后是编译通过的。你只要理解我说的左值右值问题就行了。
另外,C++ Primer这本书很好,里面引入了大量C++2.0的特性,因此理解上有困难是正常的,建议搭配其他低档点的C++书一起看效果更佳。但这本书对于对象模型讲的不多,如果对于很喜欢探究内存的小伙伴,建议看看C++对象模型方面的书,侯捷老师有翻译过,记得他翻译了两版,一般是03年的,一版是12年的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2019-1-9 17:19:19 | 显示全部楼层
luvmdy 发表于 2019-1-9 16:05
你的问题和这个应该和这个有异曲同工之处“initial value of reference to non-const must be an lvalue” ...

您说的C++ 2.0是C++11吗?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-1-9 18:39:51 | 显示全部楼层
竟无语凝噎 发表于 2019-1-9 17:19
您说的C++ 2.0是C++11吗?

是的,我们习惯把C++11及之后的标准称作C++2.0
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2019-1-9 19:46:19 | 显示全部楼层
本帖最后由 竟无语凝噎 于 2019-1-9 19:59 编辑
luvmdy 发表于 2019-1-9 16:05
你的问题和这个应该和这个有异曲同工之处“initial value of reference to non-const must be an lvalue” ...


如果按照您说的这样理解的话;
因为const 的引用是一个常量,是一个右值。
但是
Record lookup(Phone);
Record lookup(const Phone); 这个的const 也是右值啊, 这个为什么就会产生二义性而

Record lookup(Account &);
Record lookup(const Account &);
却不会产生二义性?

这个我想了一下不知道对不对:
const int  和 int 作为形参均既可以左值又可以右值,所以可以。
但是引用的形参不行。


如果上面的理解正确的话
那么
Record lookup(Account *);
Record lookup(const Account *);
该如何解释呢?

这个我的理解是  传入的参数是一根指针,都是指针变量而非常量,const 影响的是指针指向的数值(加const的表示指针指向的是常量,不加表示指向的是变量)。 那么在这里我的理解是对于传入的指针变量,两个函数是没有区分性的,也即在调用的时候会产生二义性。 所以个人认为这里不是重载
我的理解问题出现在哪里呢?

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2019-1-11 08:56:25 | 显示全部楼层
luvmdy 发表于 2019-1-8 17:26
Record lookup(Phone);
Record lookup(const Phone);
因为这俩声明的参数列表都是形参,当用实参给形参 ...

十分感谢您的回复,解决了我的问题
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-10-3 04:30

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表