C ++,类,常量和奇怪的语法

如何解决C ++,类,常量和奇怪的语法

| 我今天正在重新阅读c ++入门(第四版)-有关成员函数和const引用等部分,然后我想到了这个奇怪的小程序:
using std::cout;
using std::endl;

class ConstCheater
{
public:
    ConstCheater(int avalue) : ccp(this),value(avalue) {}
    ConstCheater& getccp() const {return *ccp;}
    int value;
private:
    ConstCheater* ccp;
};

int main()
{
    const ConstCheater cc(7); //Initialize the value to 7
    cout << cc.value << endl;
    cc.getccp().value = 4;    //Now setting it to 4,even though it\'s const!
    cout << cc.value << endl;
    cc.value = 4;             //This is illegal
    return 0;
}
我的问题是-为什么C ++允许这样的语法?为什么在声明为const的类中编辑普通数据成员? const的POINT不是为了使您无法修改值吗?     

解决方法

我会说托尼(Tony)标记为正确的答案是错误的,而迈克尔·伯尔(Michael Burr)的答案是正确的。 更明确地说出他的话(至少对我来说): 有两个可能引起误解的地方: 隐式const的工作方式 在构造const对象期间解释
this
的方式 1.隐式常量 隐式const(当成为
const
时在
ConstCheater
内部的含义)不会将
cc
变成
pointer-to-const
而是变成
const-pointer
,也就是说,当您执行此操作时:
  const ConstCheater cc(7); 
内部来自:
  ConstCheater * ccp;
...至...
  ConstCheater * const ccp;
而不是...
  const ConstCheater * ccp;    
这可能是预期的。 2.
const
物体的构造 不过,更奇怪的是,允许将
this
传递给构造函数中的
cpp
\的初始值设定项,因为人们认为ѭ1should应被视为
pointer-to-const
,因此不是传递给
const-pointer
的有效值。 这就是说人们可能会期望:
 ...: ccp(this) ... // expected to fail but doesnt
之所以失败,是因为从概念上讲,您可能希望这等效于:
 const ConstCheater         cc(7);
 const ConstCheater * const this = &cc; // const-pointer-to-const
因此,您会认为:
 ConstCheater * const ccp = this; //expected error!
会失败!但这不是因为显然在构造过程中显然将
this
当作是:
 const ConstCheater * this = &cc; 
因此该对象在构造过程中实际上不是常量。 我不确定我是否完全理解其原因,但迈克尔·伯尔(Michael Burr)指出,提供预期行为似乎存在逻辑和技术障碍,因此该标准似乎可以消除当前有些奇怪的行为。 我最近问了一个相关的问题:为什么C ++没有const构造函数?但是到目前为止,我还没有真正完全理解为什么它站不住脚的原因,尽管我认为这将给C ++开发人员带来负担,他们必须为他们想要创建const对象的任何类定义一个笨拙的const构造函数。 。     ,即使
getccp()
const
方法,它也不保证您对返回的引用进行操作。该方法本身不会修改对象,因此不会违反规则。 如果返回a24ѭ,那就不一样了。 如您的示例所示,
const
的复杂性远不只是将其应用于对象。 C ++常见问题解答中有一个有关const正确性的部分,尤其涉及您在此处强调的情况。     ,允许构造函数修改“ 3”对象的值,是的。但是,如果不是,那该怎么办呢? 由于构造函数具有这种访问权限,因此可以将其“转发”给其他人或“保存”以供以后使用。当然,这样做可能不是一个好主意。 在这种情况下,C ++的安全机制不会阻止您构建格式错误的程序。 C ++并非万无一失。因此,请小心!     ,在构造函数完成其操作之前,对象不会变为const。因此,“ 1”是存储非常量内存的指针,但此后不久便发生变化。这就是为什么它首先允许分配的原因,因为您没有做错任何事情。这意味着ѭ13是指向const的指针,但是编译器没有意识到这一点。它没有办法;毕竟,您将其声明为非常量。这仍然是未定义的行为,不是您的编译器真正希望能够帮助您捕获的类型。     ,真正的问题不是ѭ29的行为-行上没有错误:
const ConstCheater cc(7);
它使用应为constwith1ѭ指针的指针初始化非const指针。但是,构造函数不能为
const
(9.3.2 / 5,但是稍加思考,就应该清楚为什么)。因此,允许构造函数使用指向const对象(或即将成为const的对象)的指针来初始化非const指针。那就是你在开车的洞。 关于为什么允许它,我想标准很难尝试去封闭漏洞,因为它必须枚举构造函数的ѭ1all必须被视为
const
的所有方式以及所有方式。构造const对象时,必须将其视为“ 35”。这似乎是一项艰巨的任务。     ,您的对象不是完全不变的:它只是您创建的指向它的引用,它是恒定的。     ,您正在制作
const
是指
ConstCheater
ConstCheater
中的任何内容都不会使
value
成为
const
。     ,
const
限定符限制在对象上调用非const方法,因此问题是您的设计允许您通过const方法为成员提供非const引用。 常见的方法是
      Member& getccp()       {return *member;}
const Member& getccp() const {return *member;} 
在某些情况下,如果对象的逻辑一致性不受其成员的外部修改的影响,则可以允许
      Member& getccp() const {return *member;}
逻辑和形式常数差异的另一个例子是
mutable
成员。即mutable可以是在最后一个“ 3”方法调用时计算的术语,如果您在下一次调用时获得相同的输入,则可以轻松地返回存储的值。     

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-