- #include
- #include
- using namespace std;
- class Dog
- {
- public:
- Dog(unsigned en =0) :energe(en){}
- voidbark()const
- {
- for(size_t i =0; i < energe; i++)
- cout <<"wang wang!\n";
- }
- void feed(unsigned add)
- {
- energe += add;
- }
- private:
- unsigned energe;
- };
- int main()
- {
- Dog dog;
- dog.feed(2);
- dog.bark();
- return 0;
- }
翻译转换
现在的 C++ 编译器可能不是这样的工作的,但是,如果你使用这个转换方式去应用到实际的编程的代码分析中,很多代码和语法特性就会迎刃而解。
- //原型转换
- voidfeed(constDog*this);
- voidfeed(Dog*this,unsigned add);
- //调用的转换dog.feed(2); -----> feed(&dog ,2);
- dog.bark(); -----> bark(&dog);
顶层 const:指针变量本身是常量。(顶层 const 不适合引用,因为引用天生就是一个常量,始终引用一个对象,直到消亡)
如 int* const p = &a;
底层 const:变量指向(或者引用)的对象被视为常量。(注意这里的用词:被视为,因为对象不一定就是常量,也可能是底层 const 指针、引用的一厢情愿)
如 const int*p ; int const *p; 这二者写法等价
const int& r;
一个非底层 const 指针,它对它指向的对象有 读、写的权利,因此,为了确保数据安全,它仅能指向非常量对象。
- inta=1;
- const intb =2;
- int*p1 = &a;//OK
- p1 = &b;//Error不允许
一个底层 const 指针,他对它指向的对象仅有读的权利。因此,它可以指向常量和非常量。
- inta=1;
- const intb =2;
- const int*p1 = &a;//OK
- p1 = &b ;//OK
举例说,下面 2 个函数可以重载。
- void foo(const int * p); //A
- void foo(int * p); //B
编译器在重载解析时,根据传递的参数来判断调用哪一个版本。
当仅存在版本 A 时,若传递的是非常量 int 的指针,或常量 int 的指针,都可以成功调用。
当仅存在版本 B 时,若传递的是非常量 int 的指针,可以成功调用,但不允许传递常量 int 的指针。
当 A、B 都存在,重载时,若传递的是非常量 int 的指针,则优先使用版本 B,因为这是最匹配的。
若传递的是常量 int 的指针, 则使用版本 A。
另外,参数本身是否是 const 不作为重载的依据,下面的不能重载。
- void foo(const int a);
- void foo(int a);
- //C语言中,参数修饰为const和不使用const修饰 被编译器一样对待,C++为兼容C,也使用了这个策略。因此二者等价。
在上面的 Dog 类代码中,如果去掉 bark 函数后的 const 修饰符,并试着用一个 const 对象去调用 bark 函数,则发现编译器报错。
- void bark()
- {
- for(size_t i =0; i < energe; i++)
- cout <<"wang wang!\n";
- }
- /////////////////////////
- const Dog dog;
- dog.bark(); //错误提示为类型不兼容
抛开代码,从业务逻辑上来看,bark 函数只是在屏幕上输出消息,根本不会改变对象的状态,那即便是 const 对象,也必须能成功调用啊。
这里报错显然是 bark 函数的问题:应该定义为 const 函数,这点大家都是很清楚的。但是为什么要这样的呢?
按照最开始介绍的分析方法,发生错误的代码等价与下面的 C 代码。
- const Dog dog;
- bark( & dog) //转化后的bark的原型:void bark(Dog*this);
显然,将常量的指针赋值给非常量指针是不允许的。
再比如,C++ 标准库中的 string 类,它的用于获取字符串长度的成员函数都是 const 修饰的。如果不是这样的话,那么字符串常量就不能获取他们的长度了,这简直荒谬!
- size_type size()const;
- size_type length()const;
成员函数同时存在 const 版本和非 const 版本?可以重载?是的。
同样,先按照最开始介绍的第 1 条分析方法,转换为 C 代码。然后根据第 3 条的分析就可以了。这里不再赘述。
最常用的就是,按照约定当重载索引运算符 [ ] 时,会同时编写一个 const 版本和非 const 版本。
例如 std::vector 的 [ ] 运算符函数
- referenceoperator[]( size_type pos );
- const_reference operator[]( size_type pos )const;
1、如果一个成员函数在逻辑上不会修改对象的状态(字段),就应该定义为 const 函数
2、
如果对象是 const,则它只能调用 const 成员函数。
如果对象是普通的非 const 对象:
调用的某个成员函数是非 const 函数,则理所当然调用它。
调用的某个成员函数是 const 函数,则当然也可以调用他。(底层 const 指针可以指向非常量对象)
调用的某个成员函数同时存在 const 版本和非 const 版本,则优先调用非 const 成员函数,编译器总是使用最匹配的版本。
来源: http://www.cnblogs.com/lulipro/p/6855799.html