免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 4631 | 回复: 11
打印 上一主题 下一主题

[C++] 重载和const的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-09-25 10:31 |只看该作者 |倒序浏览
我的类有这三个方法:
                inline Context& operator =(const Context& _xctx){this->assign(_xctx.getAll());return *this;} //1
                void assign(const map<string,string> _mp);  //2
                map<string,string> getAll(){return mp;}  //3
private:
  map<string,string> _xctx;
其中方法1在编译时报: The non-const member function "Context::getAll()" is called for "const Context"
好像是说 getAll是非const方法,被方法1调用了。但我把方法3前增加了const ,也一样报这个错。请大家能否解释下吗?

另外,const到底什么时候用?有人说是“不希望变量被修改时用”,那这跟方法3是否设为const有何关系?返回值是不会再被方法改掉的。还有传对象做参数,若不加const,好像也只是值传入,又怎么会被修改呢?有点不明白,也请指点一下。

论坛徽章:
0
2 [报告]
发表于 2008-09-25 10:45 |只看该作者
那就是说参数里加了const,一般函数本身也必须是const才行?

论坛徽章:
0
3 [报告]
发表于 2008-09-25 12:31 |只看该作者
原帖由 j1111011 于 2008-9-25 10:38 发表
非 const 函数调用 const 参数,不能保证参数不被修改,在函数那加个const


应是返回参数要是const 引用, 因为传入的参数是const的, 所以返回引用时也必须是const.
并不一定要函数是const的常成员函数!

论坛徽章:
0
4 [报告]
发表于 2008-09-25 12:50 |只看该作者
原帖由 j1111011 于 2008-9-25 10:38 发表
非 const 函数调用 const 参数,不能保证参数不被修改,在函数那加个const

扯淡。

论坛徽章:
0
5 [报告]
发表于 2008-09-25 12:56 |只看该作者
原帖由 jchc 于 2008-9-25 10:31 发表
我的类有这三个方法:
                inline Context& operator =(const Context& _xctx){this->assign(_xctx.getAll());return *this;} //1
                void assign(const map _mp);  //2
                map getAll(){return mp;}  //3
priv ...

const Context& _xctx是個const,只能調用const方法,因此:
map getAll() const {return mp;}
4、const:表明该对象是read only的,也可以用来表示常量,但不是所有的编译器都支持这个特性。这也就是为什么const int X = 10; T a[X];在使用某些编译器编译时是非法的。

    * 用来保护对象不受修改。
    * const成员函数,只能访问const成员——当然不包括logical constness。
    * const参数,表明该参数不可被函数修改,一般作用于T*或者T&。
    * T * const和T const *(const T*)的区别。从右向左读就能明白区别。传参时,T * const与T*等价。还有const T * const,表明该对象以及其指向的对象都是read only的。
    * const返回值:返回的对象是readonly的。

注:对于一个对象的const成员函数来说,有bitwise和logical的constness之分。logical的不多说,通过用 mutable关键字修饰数据成员即可。而对于bitwise的,有一点需要注意:当类A包含B*数据成员,A的const成员函数只要不修改B*就不破坏bitwise的constness,也就是说,该成员指向的对象被修改不违背bitwise的constness。

http://blog.chinaunix.net/u/12783/showart_548200.html

论坛徽章:
0
6 [报告]
发表于 2008-09-25 13:04 |只看该作者
原帖由 j1111011 于 2008-9-25 12:06 发表

class _Cls{
&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;&nbsp;body;
&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;&nbsp;getBody()const {
&nbsp;&nbsp;&nbsp;&nbsp; ...

兄弟,你舉的例子也書名不了問題,而且是錯的。
const成員函數中的const是用來修飾隱含的this參數的。

论坛徽章:
0
7 [报告]
发表于 2008-09-25 13:30 |只看该作者

回复 #1 jchc 的帖子

                map<string,string> getAll(){return mp;}  //3
但我把方法3前增加了const ,也一样报这个错。请大家能否解释下吗?


               map<string,string> getAll() const {return mp;}  //3

这才是表示一个成员函数是const的,意思是调用这个成员函数不会改变该对象。


http://blog.chinaunix.net/u/23408/showart.php?id=191168

关键字 const 和 mutable
const 修饰常量与形式参数

const 可以而且应当尽量用来修饰常量(或函数的形式参数)告诉编译器该数据不会改变。将常量用“const”标明的最大好处是可以在编译器就发现不期望的修改。而且也有助于代码优化——不论是编译器还是程序员自己进行优化。比如说“copy on write”。
const 对传值调用也有意义

void f(const int i){
    ++i; //error: increment of read-only parameter `i'
}

基本类型的常量可以定义在头文件中

const常量默认为“internal linkage”,所以const常量定义在头文件中是合法的。但是这么做会导致每个包含该头文件的编译模块拥有一份该常量的拷贝。

一般来说,基本类型的常量(尤其是整型)可以定义在头文件中,好处是:

    * 可以确保各个编译模块中的常量保持一致。
    * 可以用整型常量来定义静态数组。

静态数组长度一般用整型字面常量或者相应的宏表示(T array[LEN])字面常量的缺点显而易见。宏应用在此处虽然没什么大问题但毕竟还是存在一定缺点。用整型常量相对来讲是最好的选择。可是由于定义静态数组时数组长度必须已知,所以整型常量的值必须在静态数组定义时可见。如果整型常量定义在另一个.cc文件中,就无法用该常量来定义数组。反之,如果该常量定义在头文件中且该头文件又被包含则可。

错误:

// a.h:
    extern const int ARRAY_LEN;
// b.cc:
    #include "a.h"
    const int ARRAY_LEN = 10;
// c.cc:
    #include "a.h"
    int a[ARRAY_LEN]; // error

正确:

// a.h
   const int ARRAY_LEN = 10;
// c.cc
   #include "a.h"
   int a[ARRAY_LEN]; // ok

但是复合类型常量别定义在头文件中

例子(跳过?)
test.h

#include <iostream>
#ifndef TEST_H
#define TEST_H 1
using namespace std;

class CA
{
  public:
    static int i;
    CA() { ++ CA::i;}
};

const CA a;
#endif // TEST_H

test1.cc

#include "test.h"
void f()
{
    cout << a.i << endl;
}

test.cc

#include "test.h"
void f();
int CA::i = 0;

int main(int argc, char argv[]){
    f();
    cout <<a.i <<endl;
    return 0;
}

compile & result (cygwin)

g++ test.cc test1.cc

result:
2
2

const 修饰成员函数

const 还可以用来修饰成员函数以表明它不会破坏对象的逻辑不变性。
物理不变与逻辑不变

逻辑不变(Logical Constness)指的是对象的呈现给用户的状态不变,但它的成员变量是否变化则不一定。与逻辑不变相对应的还有物理不变(Physical Constness)。所谓物理不变指的是对象的任何成员变量都不作任何改动。有时两者是一致的,但有很多时候两者并不一致。例如:假设有如下多线程环境下的set类,它的成员函数getData()获取指定键值的元素。

例子: MtSet

template <typename _K_,
          typename _Compare_=
                    std::less<_K_> >
class MtSet{
  public:
    _K_ getData(const key_type& key) const{
        MutexLock lock(_mutex_);
        return  (_set_.find(key));
    }

  public:
    std::set<key_type> _set_;
    mutable Mutex _mutex_;
  // ...
};

显然,从逻辑上说getData()不修改调用它的对象,即不破坏对象的逻辑不变性;但是为了线程同步,getData()必然要先锁住互斥锁(_mutex_),也就必然破坏对象的物理不变性。
关键字 mutable

上一节讲到const成员函数应当保持对象逻辑上不变。但是一个成员函数被定义成 const成员后,编译器禁止它修改对象的任何属性。如果成员函数确实需要在不破坏对象逻辑不变性的前提下修改某一属性就需要借助关键字 mutable 了。

关键字 mutable 表示被修饰者在任何情况下都不为常量。上例中MtSet把_mutex_定义成mutable变量。不论MtSet的对象是否为常量,_mutex_都是一个“变”量。

[ 本帖最后由 lgfang 于 2008-9-25 13:40 编辑 ]

论坛徽章:
0
8 [报告]
发表于 2008-09-25 13:46 |只看该作者
lgfang
风云使者 总结的好!!

论坛徽章:
0
9 [报告]
发表于 2008-09-25 13:47 |只看该作者
The non-const member function "Context::getAll()" is called for "const Context"

这个错误是说:const Context对象调用了非const的成员函数getAll(),造成这个错误的原因是this指针。

众所周知,成员函数其实是隐含一个this指针的,在非const成员函数中,this指针是非const的,例如你所定义的getAll()函数:
map<string,string> getAll(){return mp;}

注意到,非const指针不能指向const对象,而你的程序中
inline Context& operator =(const Context& _xctx){this->assign(_xctx.getAll());return *this;}

_xctx是const对象,调用getAll()会导致将_xctx赋值给一个非const的this指针,所以造成错误。
正确的做法可参见楼上

论坛徽章:
0
10 [报告]
发表于 2008-09-25 13:52 |只看该作者
原帖由 j1111011 于 2008-9-25 13:43 发表

??错了?
我用VC Express 2008编译通过了!怎么会错误嘞??

不是代碼本身錯,而是代碼要表達的意思以及你的觀點錯了。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP