C++中常量成员函数的含义

本文内容来源:《C++必知必会》

使用常量成员函数可以改变对象的逻辑状态,虽然对象的物理状态没有发生改变。考虑如下代码,它定义了一个类X:

class X{
public:
X():buffer_(0),isComputed_(false){}
//...
void setBuffer(){
int *tmp = new int[MAX];
delete [] buffer_;
buffer_ = tmp;
}//setBuffer void modifyBuffer(int index, int value) const{
buffer_[index] = value; //Valid but not suggested!
}//end of modifyBuffer int getValue() const{
if( !isComputed_){
computedValue = expensiveOperation(); //Error!
isComputed_ =true; // Error!
}
return computedValue_;
}//end of getValue
private:
static int expensiveOperation();
int *buffer_;
bool isComputed_;
int computeValue_;
}

  

setBuffer函数必须是非常量的,因为它要修改其所属的X对象的一个数据成员。然而,modifyBuffer可以被合法地被标为常量,因为它没有修改X对象,它只是修改X的buffer_成员所指向的一些数据。这种做法是合法的,但是很不道德。

有时一个被声明为常量的成员函数必须要修改其对象,这常见于利用"lazy evaluation"机制来计算一个值时,换句话说,只有当第一次提出请求,才计算值,目的在于在该请求根本没有发出的其余情形下,让程序运行得更快。在这种情况下会有一个进行转型犯错的诱惑,为的是能够让事情变得更好,即将该成员函数声明为常量。

int getValue() const{
int (!isComputed_){
X *const aThis = const_cast<X *const>(this);
aThis->computedValue = expensiveOperation();
aThis->isComputed_ = true;
}
return computedValue_;
}
千万抵制住这个诱惑!处理这种情形的正确方式是将有关数据成员声明为mutable:

class X{
public:
//...
int getValue() const{
int (!isComputed_){
computedValue = expensiveOperation();
isComputed_ = true;
}
return computedValue_;
}
private:
mutable bool isComputed_; //现在可以修改了。
mutable int computedValue_; //现在可以修改了。
}

类的非静态数据成员可以声明为mutable,这将允许它们的值可以被该类的常量成员函数(当然也包括非常量成员函数)修改,从而允许一个“逻辑上为常量”的成员函数被声明为常量,虽然其实现需要修改该对象。

以下例子可以解释函数重载解析是如何区分一个成员函数的常量和非常量版本的。

class X{
public:
//...
int &operator[] (int index);
cost int &operator[](int index) const;
}; int i = 12;
X a;
a[7] = i;// this 是 X *const,因为a是非常量
const X b;
i = b[i]; // this 是 const X *const, 因为b 是常量

考虑如下具有两个常量参数的非成员二元操作符

X operator+(const X &, const X &);

如果决定声明一个与此重载操作符对应的成员形式的对应物,应该将其声明为常量成员函数,此目的是为了保持左实参的常量性质。

class X{
public:
//...
X operator+(const X &rightArg); // 左边的参数是非常量
X operator+(const X &rightArg) const; //左边的参数是常量
};
 
总结:
常量成员函数声明:如:int get() const;
规则:
1.常量成员函数不修改对象。
2.常量成员函数在定义和声明中都应加const限定
3.非常量成员函数不能被常量成员函数调用,但构造函数和析构函数除外。
4.常量(const对象)对象只能调用常量成员函数。(const对象的数据成员在对象寿命周期内不能改变,因此其只能调用常量成员函数)。
意义:
1.使成员函数的意义更加清楚,将成员函数分修改对象和不修改对象两类。
2.增加程序的健壮性,常量成员函数企图修改数据成员或调用非常量成员函数,编译器会指出错误。
原因:
     对于X类型的非常量成员函数而言,其this指针的类型是 X * const,该指针自身是常量;但是对于X类型的常量成员函数而言,其this指针的类型是const X * const,是一个常量指针。
 

<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">

 
 
 
 

C++中常量成员函数的含义的更多相关文章

  1. C++中的const成员函数(函数声明后加const,或称常量成员函数)用法详解

    http://blog.csdn.net/gmstart/article/details/7046140 在C++的类定义里面,可以看到类似下面的定义: 01 class List { 02 priv ...

  2. C++ 之 常量成员函数

    类的常量成员函数 (const member function), 可以读取类的数据成员,但是不能修改. 1  声明 1.1  const 关键字 在参数列表后,加 const 关键字,声明为常量成员 ...

  3. C++ const常量对象、常量成员函数和常引用

    01 常量对象 如果不希望某个对象的值被改变,则定义该对象的时候可以在前面加const关键字 class CTest { public: void SetValue() {} private: int ...

  4. 总结C++中取成员函数地址的几种方法

    这里, 我整理了4种C++中取成员函数地址的方法, 第1,2,4种整理于网上的方法, 第3种cdecl_cast是我自己想到的. 其中, 第4种(汇编)的方法不能在VC6上编译通过. 推荐使用第1,2 ...

  5. 【转】总结C++中取成员函数地址的几种方法

    转自:“http://www.cnblogs.com/nbsofer/p/get_member_function_address_cpp.html” 这里, 我整理了4种C++中取成员函数地址的方法, ...

  6. C++官方文档-常量成员函数

    #include <iostream> using namespace std; class MyClass { public: int x; static int n; const in ...

  7. C++(十六) — 类中引用成员函数、命名空间的使用

    1.为什么类中引用成员函数? 类将属性和方法做了封装.类是一种数据类型,也就是:固定大小内存块的别名. 类的定义是一个抽象的概念,定义时不分配内存,当用类定义对象时,才分配一个固定大小的内存块. 此时 ...

  8. 【Java.Regex】使用正则表达式查找一个Java类中的成员函数

    代码: import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; imp ...

  9. 在C语言结构体中添加成员函数

    我们在使用C语言的结构体时,经常都是只定义几个成员变量,而学过面向对象的人应该知道,我们定义类时,不只是定义了成员变量,还定义了成员方法,而类的结构和结构体非常的相似,所以,为什么不想想如何在C语言结 ...

随机推荐

  1. Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第五章:渲染流水线

    原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第五章:渲染流水线 学习目标 了解几个用以表达真实场景的标志和2D图像 ...

  2. innerHTML属性的内存和性能问题

    使用innerHTML替换子节点可能会导致浏览器的内存占用问题,尤其是在IE中,问题更加明显.在删除带有时间处理程序或引用了其他js对象子树是,就有可能导致内存占用问题.假设某个元素有一个事件处理程序 ...

  3. ACK容器服务发布virtual node addon,快速部署虚拟节点提升集群弹性能力

    在上一篇博文中(https://yq.aliyun.com/articles/647119),我们展示了如何手动执行yaml文件给Kubernetes集群添加虚拟节点,然而,手动执行的方式用户体验并不 ...

  4. docker images列出镜像

    命令:docker images Usage: docker images [OPTIONS] [REPOSITORY[:TAG]] List images Options: -a, --all Sh ...

  5. 2-3-4 tree留坑

    #include<bits/stdc++.h> #define LL long long #define pii pair<int,int> #define mp make_p ...

  6. Top 10 open source projects of 2015

    Top 10 open source projects of 2015 Posted 15 Dec 2015Jen Wike Huger (Red Hat)Feed 188 up 31 comment ...

  7. hdu 1434 幸福列车 (Leftist Tree)

    Problem - 1434 网上题解是普通的堆合并,都是用优先队列直接做的.可是正解的堆合并应该是用左偏堆或者斐波那契堆的吧,不然O(X * N ^ 2)的复杂度应该是过不了的.斐波那契堆的实现相对 ...

  8. php-max_execution_time

    有时候我们需要跑一个脚本,比如执行几十万个请求.如果你使用浏览器,请求服务器.这时就会出现执行中断,因为超时了.我们可以通过下面的方式: 修改php.ini配置文件 max_execution_tim ...

  9. HDU1711 Number Sequence 题解 KMP算法

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1711 题目大意:最基础的字符串匹配,只不过这里用整数数组代替了字符串. 给你两个数组 \(a[1..N ...

  10. 在 Jenkins Windows Agent 节点上执行 Shell 命令

    Jenkins 在 Windows agent 上执行shell 命令,听起来很有意思,以下方法可以在 Jenkins 中执行一些简单的 shell 脚本,如果是复杂脚本就交给 Linux agent ...