类中的const后置函数可操作常量对象如何理解?

fnwyq 2008-03-26 05:27:55
大家好!
如下:

class ClassName
{
public:
int Fun() const;
.....
}

请问Fun中可操作常量对象如何理?
...全文
1010 30 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
30 条回复
切换为时间正序
请发表友善的回复…
发表回复
fnwyq 2008-04-02
  • 打赏
  • 举报
回复
感谢LS,几个地方讲得很经典!
但是对于“③ const 参数修饰 和 参数返回类型的const修饰 ”和总结部分的<2>,我想补充或者说不同见解如下:

限定函数的传递值参数:
void Fun(const int Var);
分析:上述写法限定参数在函数体中不可被改变。由值传递的特点可知,Var在函数体中的改变不会影响到函数外部。所以,此限定与函数的使用者无关,仅与函数的编写者有关。 结论:最好在函数的内部进行限定,对外部调用者屏蔽,以免引起困惑。如可改写如下:
void Fun(int Var)
{
const int & VarAlias = Var;
VarAlias ...
....
}


限定函数的值型返回值:
const int Fun1();
const MyClass Fun2();
分析:上述写法限定函数的返回值不可被更新,当函数返回内部的类型时(如Fun1),已经是一个数值,当然不可被赋值更新,所以,此时const无意 义,最好去掉,以免困惑。当函数返回自定义的类型时(如Fun2),这个类型仍然包含可以被赋值的变量成员,所以,此时有意义。

用于指针的两种情况分析:
int const *A; file://A可变,*A不可变
int *const A; file://A不可变,*A可变
分析:const是一个左结合的类型修饰符,它与其左侧的类型修饰符和为一个类型修饰符,所以,int const 限定 *A,不限定A。int *const 限定A,不限定*A。
kuronca 2008-03-31
  • 打赏
  • 举报
回复
Const 最早想法是用于取代预处理器#define 这个宏,从而形成常量的概念。针对常量const对象,const指针及指向const的指针,函数const类型参数,const 函数返回类型, const类成员,及const成员函数,及对const最后理解的一些总结来描述 const。
① const对象和const类型的对象
对于这两个概念的描述如下
1. int const Object; //Object是一个const量是不可以被修改 Object = 2;Error
2. const int Object; //Object是 const int型他所存放的内容不可以被修改
对于1,2这两种const用于对象,表述虽然不同但是效果是一样的。因为对象本身存放着内容对对象的改变就是对于对象内容的改变,同样改变后者也是在改变前者。所以语义上一样的。
② const指针 和 指向const的指针 及两者结合
对于三个概念描述如下
1. int* const p; //指针p是const不能被修改 例如p++; //修改p本身会Error
//修改p指向内容 *p = 2; //OK
2. const int* p; //p是指向一个整形常量的指针指向的内容不可以改变 p++;//OK
// *p = 2; //Error
3. const int* const p; //指针p本身是不能被修改并且p所有有效的内容也不能被
//修改 *p = 2; Error 和 p++; Error
③ const 参数修饰 和 参数返回类型的const修饰
1.const 参数修饰
此时函数参数修饰 const的具体用法 ① ②中用法是一样的
例如 void Fun( const int I ) { I++;} //Error不能修改常量I
2.const修饰函数返回类型用法也是类似于 ①②中,仅仅修饰的对象变化变成一个返回对象
例如:const int Fun() { static int I; return I;}
int Res = (Fun())++ //Error不能修改常量返回对象
④ const类成员 和 const 成员函数
1. const成员
类const成员在构造期间会允许被初始化并且在以后不能被改变。我们就可以知道类const成员和一般const 变量是有所不同的,类const成员是对应于每个对象而言才有意义。因为他在构造期被初始化,只有当类实例化后才会进行构造。所以类const成员可以这样描述: 在类的每一次实例化时被初始化,在这个对象的生存周期中不可改变。
2. const 成员函数
描述: void Class::MemberFun() const {}; //此时这个const修饰的this所有类成员变量都不允许在这个函数体作用后被修改。这在设计上会带来一些好处,能防止你意外的处理带来的问题。
总结:
<1> const 常量 一般编译器不会分配空间只是维护一张表。而当extern 外部引用这个常量或者“&”对这个常量取地址时,编译器才会为其分配地址。Const本身的机制比较复杂。
<2> const 记忆法则 const修饰后面一个最近的名称。我曾初学的时候被const 修饰搞的糊里糊涂,后来慢慢的总结我觉得这样理解最容易的。
例子: const int I; 此时const仅仅修饰int 表明 I不是一个常量但是I的内容是常量。因为c/c++表达 对I的改变就是对I内容的改变所以 I也类似一个const。大家不妨可以用指针const修饰试试理解会有帮助的我想。
<3> 对于所有非const 类型可以无条件转化为 const类型,但是后者不能自动转化为前者除非显式的强制转化去掉const性。这样做是有意义的,因为const类型是非const的一个子集是一种特殊,由普遍转化为特殊是合理的,就象模板特化,继承的向上映射都是有意义的。
<4> 记住所有const修饰的内容并不是永远不可改变,如果人为的强制转化编译器是不会提醒的。因为它没有义务这么做,所以我们对其转化时要小心。
<5> 在const类成员函数处理时,我们引入了mutable修饰类成员变量,经过其修饰的成员变量可以在const类成员函数中被修改,编译器是允许的。而其他未被mutable修饰的成员还是按照const规则不能在const成员函数中被改变。
--------------------------------------------------------------------------------



函数后面加“const”与不加是两个不同函数,如:

#include

using namespace std;

class A
{
public:
A(int i, int j){a = i; b = j;}
void print();
void print() const;
private:
int a, b;
};

void A::print()
{
cout << "hello!" << a << b << endl;
}
void A::print() const
{
cout << "hello const!" << a << b << endl;
}

int main()
{
A ss(3,6); // 定义A的对象时,没有用“const”
ss.print();
A const dd(20,2); // 定义A的对象时,用了“const”
dd.print();
}
xuewei198198 2008-03-30
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 cad_vc 的回复:]
class ClassName
{
public:
int Fun() const;
.....
}

类的非静态成员函数有个this指针,函数后面的const就是修饰this的;

int Fun() const; == int Fun(const ClassName* const this);
[/Quote]
const 对象、指向const对象的指针或引用只能用于调用其const成员函数,如果尝试用它们来调用非const成员函数,则是错误的。
pzhuyy 2008-03-30
  • 打赏
  • 举报
回复
Int Fun () const; Such definition is the Fun statement for often the
member function, its function is may quote often in the object data
member, but cannot revise wants to revise must state often the object
in data member with mutable

Often the object is cannot transfer its non- const type
regarding the member function, therefore needs to define often the
member function to quote
xrongfu 2008-03-29
  • 打赏
  • 举报
回复
同意6楼的看法
paidfighting 2008-03-29
  • 打赏
  • 举报
回复
[Quote=引用 20 楼 fnwyq 的回复:]
不知道什么情况下才适合这样用?或者说怎样去体会这一用法的精髓呢?..[/Quote]

如果你写一个大的工程,当某个对象的内容出现了意外的变化时,你可能需要去检查所有非const的函数,有了const,检查工作大大减少

而对于const对象(它也只会调用const成员函数),你可以放心使用它,因为使用前和使用后它的状态完全不变
xue100200 2008-03-29
  • 打赏
  • 举报
回复
首先,int Func() const{...}中的const表示的是{...}里引用的外部变量(不管是全局变量的还是成员变量)不会做修改。
然后,关键字mutable相当于告诉编译器“就算是有const的限定,这个变量也要改”,编译器看见这个关键字就明白了“哦,行,你改吧。”
就这样~~
fnwyq 2008-03-29
  • 打赏
  • 举报
回复
不错不错,感谢LS。
fnwyq 2008-03-28
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 steedhorse 的回复:]
“可操作常量对象”应该是翻译过来的说法吧,我猜原文应该类似于:“Can operate on const objects”,说白了,就是可以在常量对象上被调用。而一般的后面不带const的成员函数是不可以在常量对象上被调用的。
[/Quote]
steedhorse正解啊,小试了一下:
class ClassA
{
public:
void Fun1() const;
void Fun2();
...
};

这时如果有const ClassA a;
那么a只能调用Fun1而不能调用Fun2,编译器的错误提示是:
error C2662: “A::fun2”: 不能将“this”指针从“const A”转换为“A &”
其实这也和cad_vc提到的this指针相吻合,但是这种用法几乎没去用到(做得太少...),不知道什么情况下才适合这样用?或者说怎样去体会这一用法的精髓呢?..
zhangwanlong 2008-03-28
  • 打赏
  • 举报
回复
不能修改成员变量……
zhangwanlong 2008-03-28
  • 打赏
  • 举报
回复
不能修改成员变量……
fnwyq 2008-03-27
  • 打赏
  • 举报
回复
多谢大家!虽然还缺少一个“在Fun中是如何操作常量对象的实例”(因为mutable的例子只是说明了如何在Fun中操作非常量对象),显得不够完美,但已经满足。
wonder2007 2008-03-27
  • 打赏
  • 举报
回复
int Fun() const;
这样定义是将Fun声明为常成员函数,其作用是可以引用常对象中的数据成员,但是不能修改
想要修改要将常对象中的数据成员用mutable声明

对于一个常对象是不能调用其非const类型的成员函数的,所以需要定义常成员函数来引用
biosli 2008-03-27
  • 打赏
  • 举报
回复
首先,int Func() const{...}中的const表示的是{...}里引用的外部变量(不管是全局变量的还是成员变量)不会做修改。
然后,关键字mutable相当于告诉编译器“就算是有const的限定,这个变量也要改”,编译器看见这个关键字就明白了“哦,行,你改吧。”
就这样~~
fnwyq 2008-03-27
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 biosli 的回复:]
mutable 你的参数比如:

C/C++ code

class ClassName
{
public:
int Fun(const int data) const
{
m_data = data;
return 1;
}
.....
private:
mutable int m_data;
}
[/Quote]
[Quote=引用 9 楼 ttkk_2007 的回复:]
就是对成员变量,他只能读,不能写(除非成员变量是mutable的)
而且他也只能访问其他的const函数
[/Quote]
两位能不能形象解释一下mutable这个关键字?最好能从C++的实现原理上说明一下和普通未用mutable修饰的变量之间的区别,谢谢!
hxxwcc 2008-03-27
  • 打赏
  • 举报
回复

class Example
{
public:
void Foo1() const
{
Foo2();//correct
Foo3();//not correct..
mem=0;//not correct..
}
void Foo2() const;
void Foo3();
int GetMem() const{return mem;}//correct
private:
int mem;
};
hxxwcc 2008-03-27
  • 打赏
  • 举报
回复

class Example
{
public:
void Foo1() const
{
Foo2();//correct
Foo3();//not correct..
mem=0;//not correct..
}
void Foo2() const;
void Foo3();
int GetMem() const{return mem;}//correct
private:
int mem;
};
Kratos 2008-03-27
  • 打赏
  • 举报
回复
只能操作常量的函数
CrazyAzreal 2008-03-27
  • 打赏
  • 举报
回复
常量对象没看懂
是不是就是指用const修饰的变量啊?
晨星 2008-03-27
  • 打赏
  • 举报
回复
“可操作常量对象”应该是翻译过来的说法吧,我猜原文应该类似于:“Can operate on const objects”,说白了,就是可以在常量对象上被调用。而一般的后面不带const的成员函数是不可以在常量对象上被调用的。
加载更多回复(10)
目录 第1篇初级篇 第1章 初识C++ 1.1 c++简介 1.2 C++与C的区别 1.3 学习c++之前需要先学C吗 1.4 c++与其他语言的区别 1.5 c++的版本以及安装问题 第2章 做一个最简短的C4-+程序 2.1 简单的屏幕输出小程序 2.2 输出语句的使用 2.3 std::介绍 2.4 iostream与iostream.h的区别 2.5 重名问题 2.6 注释 2.7 总结 第3章 初步了解函数 3.1 一个简单的函数 3.2 函数的传参 3.3 函数的返回值、参数与变量 3.4.函数的声明与定义 3.5 局部变量 3.6 全局变量 3.7 总结 第4章 C4-+数据类型 4.1 变量的定义 4.2 将变量及数据存储在内存中 4.3 布尔型变量 4.4 字符型变量 4.5 wchart双字符型变量 4.6 整型概述 4.7 整型变量的定义 4.8 浮点型变量 4.9 常量 4.10枚举型常量 第5章 if语句与运算符 5.1 语句的定义 5.2 块的定义 5.3 表达式的定义 5.4 运算符的定义 5.4.1 赋值运算符的定义 5.4.2 数学运算符的定义 5.4.3 赋值运算符与数学运算符的联合 5.5 自加与自减 5.5.1 前置 5.5.2 后置 5.6 表达式的优先级 5.7 关系运算符 5.8 if语句 5.8.1 else语句 5.8.2 elseif语句 5.8.3 if语句的嵌套 5.9 逻辑运算符及其使用 5.9.1 逻辑“与” 5.9.2 逻辑“或” 5.9.3 逻辑“非” 5.9.4 逻辑运算符的优先级 5.9.5 运算式的真假关系 5.1 0三目运算符 5.1 0.1 三目运算符的优先问题 5.1 0.2 三目运算符的使用问题 5.1 0.3 三目运算符的型别问题 5.1 0.4 三目运算符在字符型变量中的应用 5.1 1复杂嵌套的if语句 5.1 2总结 第6章 面向对象 6.1 面向对象程序语言的主要特征 6.2 类、对象和成员 6.3 类、对象和成员的使用方法及区别 6.3.1 声明一个类 6.3.2 命名习惯 6.3.3 定义一个对象 6.3.4 类与对象的区别 6.3.5 对象与成员的关系 6.3.6 不要给类赋值 6.3.7 对象只能调用类中存在的方法 6.4 公有 6.5 私有 6.6 成员函数的声明和定义 6.7 内联函数 6.7.1 普通内联函数 6.7.2 内联成员函数 6.8 头文件与源文件 6.9 const成员函数 6.10构造函数 6.11默认构造函数 6.12析构函数 6.13析构对象数组 6.14总结 第7章 循环语句 7.1 循环语句的前身——goto语句 7.2 慎用goto语句 7.3 while语句 7.3.1 带运算符的while语句 7.3.2 以字符为条件的while语句 7.3.3 限定while循环的次数 7.3.4 continue语句 7.3.5 break语句 7.3.6 永不休止的while循环 7.4. do……while循环 7.5 for循环 7.5.1 灵活的for循环 7.5.2 条件为空的for循环 7.5.3 执行为空的for循环 7.5.4 嵌套的for循环 7.6 switch语句 7.6.1 switch语句常见错误 7.6.2 switch的菜单功能 7.7 总结 第8章 指针 8.1 什么是地址 8.2 用指针来保存地址 8.2.1 空指针 8.2.2 指针与变量类型 8.2.3 用指针来访问值 8.2.4 指针地址、指针保存的地址和 该地址的值 8.2.5 指针对数值的操作 8.2.6 更换指针保存的地址 8.3 为什么使用指针 8.3.1 栈和堆 8.3.2 用指针创建堆中空间 8.3.3 用指针删除堆中空间 8.4 动态内存 8.4.1 内存泄漏 8.4.2 在堆中创建对象 8.4.3 在堆中删除对象 8.4.4 访问堆中的数据成员 8.4..5 在构造函数中开辟内存空间 8.4.6 对象在栈与堆中的不同 8.5 this指针 8.6 指针的常见错误 8.7 指针运算 8.7.1 指针的加减运算 8.7.2 指针的赋值运算 8.7 _3指针的相减运算 8.7.4 指针的比较运算 8.8 指针 8.8.1 常量指针 8.8.2 指向常量的指针 8.8.3 指向常量的常指针 8.9 总结 第9章 引用 9.1 什么是引用 9.1.1 引用的地址 9.1.2 引用就是别名常量 9.1.3 引用对象 9.1 4空引用 9.2 函数的参数传递 9.2.1 按值传递 9.2.2 按址传递 9.2.3 按别名传递 9.2.4 让函数返回多个值 9.3 传递对象 9.3.1 按值来传递对象 9.3.2 利用指针来传递对象 9.3.3 利用cost指针来传递对象 9.3.4 利用引用来传递对象 9.3.5 到底是使用引用还是指针 9.3.6 引用和指针可以一块用 9.4 引用应注意的问题 9.4.1 引用容易犯的错误 9.4.2 引用一个按值返回的堆中对象 9.4 -3引用一个按别名返回的堆中对象 9.4.4 在哪里创建,就在哪里释放 9.5 总结 第10章 深入函数 10.1 函数重载 10.1.1 普通函数的重载 10.1.2 成员函数的重载 10.2 函数的默认参数 10.3 重载构造函数 10.3.1 成员变量的赋值与初始化 10.3.2 成员变量的初始化与构造函数 10.3.3 复制构造函数 10.3.4 构造函数和new运算符 10.3.5 再谈默认构造函数 10.4.析构函数和delete运算符 10.4..1 默认析构函数 10.4.2 调用构造函数进行类型转换 10.5 浅层复制构造函数 10.6 深层复制构造函数 第11章 运算符重载 11.1 运算符重载 11.2 在成员函数中实现自加 11.3 重载前置自加运算符 11.4 创建临时对象 11.5 创建无名临时对象 11.6 取消创建临时对象 11.7 重载后置自加运算符 11.8 重载加法运算符函数operator+ 11.9 重载赋值运算符函数operator 11.10转换类型运算符 11.10.1 温习调用构造函数实现的类型转换 11.10.2 通过构造函数将变量转换为一个对象的成员变量 11.10.3 通过operator关键字进行转换 11.11什么可以重载,什么不可以重载 第12章 继承 12.1 什么是继承和派生 12.1.1 复杂的继承和派生 12.1.2 继承和派生如何在C++中实现 12.1.3 继承的种类及语法 12.1.4 单一继承 12.2 公有型、保护型和私有型 12.3 访问权限 12.4 多重继承 12.5 继承的构造与析构 12.6 合理利用基类构造函数 12.7 继承和重载的两义性问题 12.7.1 多重继承容易产生两义性 12.7.2 继承中的重载 12.7.3 两义性的归属问题 12.7.4 减少两义性产生的混淆问题 12.7.5 虚基类不会产生两义性 12.8 总结 第13章 虚函数 13.1 指向子对象的父指针 13.2 虚函数 13.3 拳击游戏 13.4 继承是否可以实现多态性 13.5 在编译时的静态联编 13.6 在运行时的静态联编 13.7 在运行时的动态联编 13.8 在编译时的动态联编 13.9 调用虚函数 13.9.1 在虚函数中调用成员函数 13.9.2 3种调用虚函数的方式比较 13.10被继承的虚函数仍然是虚函数 13.11系统是如何调用虚函数的 13.12在虚函数中使用成员名限定 13.13虚析构函数 13.14总结 第14章 数组 14.1 数组的基本用法 14.1.1 什么是数组 14.1.2数组元素 14.1.3数组下标越界 14.1.4 倒序输出 14.1.5 将数组的下标定义为常量 14.1.6 手动操作数组元素 14.1.7 数组的初始化 14.2 数组的用途 14.2.1 求平均考试成绩 14.2.2 兔子繁殖问题 14.2.3 数字排序问题 14.3 数组在内存中的分布 14.4.输出数组名 14.5 数组名与函数 14.6 传递与接收 14.7 数组与函数 14.7.1 函数传参实例一——求数组所有元素的和 14.7.2 函数传参实例二——用递增法查找数据 14.7.3 函数传参实例三——用二分算法查找数据 14.7.4 函数传参实例四——判断数组是否按照顺序排列 14.7.5 函数传参实例五——判断数组排列方式后执行不同的函数 14.8 数组在对象中的传参 14.9 对象数组 14.10 在对象数组中初始化成员变量 14.11 指针数组 14.12 枚举常量与数组 14.13 多维数组 14.14 多维数组的初始化 14.15 字符数组 14.16 重载数组下标操作符 14.17 总结 第15章 链表 15.1 声明链表结构 15.2 简单的图书链表 15.2.1 图书链表 15.2.2 类的链表 15.3 动态链表 15.3.1 动态链表的建立 15.3.2 解决输入字符造成死循环的问题 15.3.3 动态链表的显示 15.3.4 动态链表的删除 第16章 多态性 第17章 类的特殊成员 第2篇 高级篇 第19章 代码重用 第20篇 高级篇 第20章 友元类与嵌套类 第21章 流 第22章 命名空间 第23章 模板 第24章 异常和错误处理 第25章 补充知识 附录A ASCII码对照表 附录B C++的关键字 附录C C++常用头文件列表 附录D 运算符的优先级 后记

65,187

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧