const关键字用法总结

  • const 修饰普通变量
  • const修饰指针变量
  • const修饰普通函数的值传递参数、引用&指针传递参数、返回值
  • const修饰类成员函数

一、const的作用

1.定义const常量

const int Max=100;

2.便于检查类型

const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换时可能会产生意料不到的错误。

void f(const int i)
{
        .........
}
//对传入的参数进行类型检查,不匹配进行提示

3.保护被从const修饰的变量或对象

防止意外的修改,增强程序的健壮性。

void f(const int i)
{
        i=10;//error!
}
//如果在函数体内修改了i,编译器就会报错

4.可以很方便地进行参数的调整和修改

同宏定义一样,可以做到不变则已,一变都变。

5.为函数重载提供了一个参考

class A
{
public:
  void f(int i){......} //一个函数
  void f(int i) const {......} //上一个函数的重载
};

6.可以节省空间,避免不必要的内存分配

const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝

#define Pi 3.14159              //常量宏
double a=pi;          //编译期间进行宏替换,分配内存
double b=Pi;          //再进行宏替换,又一次分配内存!
......
const doulbe  Pi=3.14159;  //此时并未将Pi放入ROM中
double a=Pi;           //此时为Pi分配内存,以后不再分配!
double b=Pi;          //没有内存分配

7.提高了效率

编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。

二、const修饰普通类型的变量

const修饰普通类型的变量被赋值后,其值不允许被修改。

const int  a = 7; 
a = 8;       // 错误,a 被编译器认为是一个常量,其值不允许修改。

三、const修饰指针变量

1.如果const位于 * 的左侧,const 修饰指针指向的内容,则内容为不可变量,简称左定值;

int a = 7;
int b = 8;
const int* c = &a;
*c = b; //错误:指针指向的内容不可修改
c = &b;//正确:指针可以修改

2.如果const位于*的右侧,const 修饰指针,则指针为不可变量,简称右定向;

int a = 7;
int b = 8;
int* const c = &a;
*c = b; //正确:指针指向的内容可修改
c = &b;//错误:指针为不可变量

3.const 修饰指针和指针指向的内容,则指针和指针指向的内容都为不可变量。

int a = 7;
int b = 8;
const int* const  c = &a;
*c = b;//错误:指针指向的内容不可修改   
c = &b;//错误:指针为不可变量

“左定值,右定向,const修饰不变量”

四、const参数传递和函数返回值。

1、const传递参数

  • 值传递的 const 修饰传递,传递过来的参数在函数内不可以改变。
void func(const int p)
{
        cout << "p = " << p << endl;
        ++p;//错误:p值不能修改
}
int main()
{
        int a = 10;
        int b = 20;
        func(a);
        func(b);
        return 0;
}
  • 当 const 参数为指针时,可以防止指针被意外篡改。
#include<iostream>
 
using namespace std;
int b = 30;
void func(int* const  p)
{
    cout << "*p = " << *p << endl;
    ++*p;//正确,p指向的值可以修改
    p = &b;//错误:p不能被修改
}
int main()
{
    int a = 10;
    func(&a);
    cout << "a = " << a << endl;
    return 0;
}
  • 自定义类型的参数传递,需要临时对象复制参数,对于临时对象的构造,需要调用构造函数,比较浪费时间,因此我们采取 const 外加引用传递的方法。并且对于一般的 int、double 等内置类型,我们不采用引用的传递方式。同时,传递的对象不能被修改。
/*定义一个学生类,获取学号*/
class Student
{
public:
    Student(){}//默认构造函数
    Student(int num):number(num){}//初始化列表
    int get_number() const //const修饰成员函数,不可修改被调用对象的值
    {
       return number;
    }
    int set_number(int num);
private:
    int number;
};
 //普通函数
void get_student_number(const Student& stu)//避免了临时对象构造
{
    cout<<stu.get_number()<<endl;
    stu.set_number(3333);//错误!对象stu不能被修改
}
 
int Student::set_number(int num)
{
    this->number = num;
    return this->number;
}
 
int main(void)
{
    Student RF(1001);
    get_student_number(RF);
    int rf_num = RF.set_number(2222);
    cout << "rf_num = " << rf_num << endl;
    return 0;
}

2、const 修饰函数的返回值【用的少,有机会用到再补充】
const 修饰自定义类型的作为返回值,此时返回的值不能作为左值使用,既不能被赋值,也不能被修改。
const 修饰返回的指针或者引用,是否返回一个指向 const 的指针,取决于我们想让用户干什么。

五、const修饰类成员函数。

  • 面向对象程序设计中,为了体现封装性,通常不允许直接修改类对象的数据成员。
  • 若要修改类对象,应调用公有成员函数来完成。为了保证const对象的常量性,编译器须区分不安全与安全的成员函数(即区分试图修改类对象与不修改类对象的函数)。例如:
const Screen blankScreen;
blankScreen.display();   // 对象的读操作
blankScreen.set(*);    // 错误:const类对象不允许修改
  • 在C++中,只有被声明为const的成员函数才能被一个const类对象调用。
  • 要声明一个const类型的类成员函数,只需要在成员函数参数列表后加上关键字const,例如
class Screen {
public:
   char get() const;
};
  • 在类体之外定义const成员函数时,还必须加上const关键字,例如
char Screen::get() const {
   return _screen[_cursor];
}
  • 若将成员成员函数声明为const,则该函数不允许修改类的数据成员。例如
class Screen {
public:
    int ok() const {return _cursor; }//读可以
    int error(intival) const { _cursor = ival; }//修改不行!
};
  • 值得注意的是,把一个成员函数声明为const可以保证这个成员函数不修改数据成员,但是,如果数据成员是指针,则const成员函数则可以修改指针指向的对象,编译器不会把这种修改检测为错误。例如
class Name {
public:
    void setName(const string &s) const;
private:
    char *m_sName;
};
 
void setName(const string &s) const {
    m_sName = s.c_str();      // 错误!不能修改m_sName;
 
    for (int i = 0; i < s.size(); ++i) 
        m_sName[i] = s[i];    // 不好的风格,但不是错误的
    //虽然 m_Name 不能被修改,但 m_sName 是 char * 类型,const 成员函数可以修改其所指向的字符。
}
  • const成员函数可以被具有相同参数列表的非const成员函数重载,例如,
class Screen {
public:
    char get(int x,int y);
    char get(int x,int y) const;
};
//在这种情况下,类对象的常量性决定调用哪个函数。
const Screen cs;
Screen cc2;
char ch = cs.get(0, 0);  // 调用const成员函数
ch = cs2.get(0, 0);     // 调用非const成员函数

小结:

  • const成员函数可以访问非const对象的非const数据成员、const数据成员,也可以访问const对象内的所有数据成员;
  • 非const成员函数可以访问非const对象的非const数据成员、const数据成员,但不可以访问const对象的任意数据成员;
  • 作为一种良好的编程风格,在声明一个成员函数时,若该成员函数并不对数据成员进行修改操作,应尽可能将该成员函数声明为const 成员函数。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值