C++ const修饰变量和修饰函数介绍

const修饰变量

关于const最常见的一个面试题是这样的:char *const和const char*有什么区别,大家都知道const修饰符代表的是常量,即const修饰的变量一旦被初始化是不能被更改的,这两个类型一个代表的是指针不可变,一个代表指针指向内容不可变,但具体哪个对应哪个,很多人一直搞不清楚。

有这样一个规律,const修饰的是它前面所有的数据类型,如果const在最前面,那么把它和它后面第一个数据类行交换.比如上面的const char*交换之后就是char const *,这样一来就很清楚了,char *const p中的const修饰的是char *(注意,我们这里把char和*都算作一种类型,这时候const修饰的是char和*的组合,也就是字符串指针),是一个指针类型,所以这时候指针p是不能变的,比如下面这段代码就会报错

代码如下:

char str1[]="str1"; 
char str2[]="str2"; 
char *const p = str1; 
p = str2;

这时候p是一个指针常量,它是不能指向别的地方的,但是它本身指向的内容是可以变的,比如下面的操作就是允许的

代码如下:

char str1[]="str1"; 
char *const p = str1; 
p[0] = 'X'; 
printf("%s", str1);

这时候str1的值就变成了"Xtr1"
我们再来看const char *p,根据前面提到的规律,将const和它后面一个类型交换变成char const *p(其实这种写法也是允许的,只是人们习惯将const写在最前面),这时候const修饰的是char,也就是说p指向的字符内容是不能变的。将上面两个例子的char *const p全部改成const char *p,则结果正好相反,第一个可以编译通过,第二个会报错。

其它时候就很好区分了,比如const int ,const string等等,总之,const修饰的是什么类型,这个类型的变量就不能被改变。

const修饰函数

先来看这样一个函数

代码如下:

const char * func(const char *str) const;

这样的函数比较夸张,有三个const,我们从左到右来一一说明:

1、第一个const修饰的是返回值,前面已经说过,这里的const修饰的是char,也就是说返回值的内容是不能被更改的
2、第二个const和第一个是一样的,这种用的比较多,它作为函数参数,表示的是这个参数在函数体内是不能被改动的(被传进来的实参并不要求是const类型),这样做是为了防止函数对实参做一些意外的操作,你试想下,当你调用一个函数时,你传进去一个变量是"hello world!",调完函数之后变成了"fuck the world!",这实在是不可忍的,所以我们在设计函数的时候,如果传进来的参数只作为读取使用,最好是将参数设成const类型。很多公司在面试让写代码的时候都会看中这个细节,你注意了这个细节不一定说明你牛逼,但你若没注意那肯定是会减分的。
3、再来说第三个const,按照我们最开始说的规律,const修饰的是它前面的所有数据类型,这里它前面的所有数据类型组合起来就是一个函数,这种类型一般出现在类成员函数里,当然,这里并不是说这个函数是不能变的,它代表的时这个函数不能改变类的成员变量,不管是public的还是private的

我们下面举例主要说明第三种情况,来看这样一个简单的程序

代码如下:

#include<stdio.h> 
 
class A 

public: 
    A() : x(0), y(0){} 
    void func(const int p) 
    { 
        x = p; 
        y = p; 
    } 
    int getY() 
    { 
        return y; 
    } 
    int x; 
private: 
    int y; 
}; 
 
int main(int argc, char* argv[]) 

    A a; 
    printf("x:%d y:%d\n", a.x, a.getY()); 
    a.func(2); 
    printf("x:%d y:%d\n", a.x, a.getY()); 
    return 0; 
}

这段代码是可以直接编译过的,运行结果是

代码如下:

x:0 y:0 
x:2 y:2

我们稍作修改,将void func(const int p)改成void func(const int p) const再编译,就会直接报错,报错的两行代码是

代码如下:

x = p; 
y = p;

也就是说const类型的函数试图去修改类的成员变量是非法的,但是有一种情况例外,我们再在上面修改的基础上做一点修改,将int x改成mutable int x,将int y改成mutable int y,这时候程序又可以正常运行了,也就是说,如果成员变量是mutable类型的,它可以在任何场景下被修改。

(0)

相关推荐

  • C++ 中const对象与const成员函数的实例详解

    C++ 中const对象与const成员函数的实例详解 const对象只能调用const成员函数: #include<iostream> using namespace std; class A { public: void fun()const { cout<<"const 成员函数!"<<endl; } void fun() { cout<<"非const成员函数 !"<<endl; } }; int

  • C++中const用于函数重载的示例代码

    常成员函数和非常成员函数之间的重载 首先先回忆一下常成员函数 声明:<类型标志符>函数名(参数表)const: 说明: (1)const是函数类型的一部分,在实现部分也要带该关键字. (2)const关键字可以用于对重载函数的区分. (3)常成员函数不能更新类的成员变量,也不能调用该类中没有用const修饰的成员函数,只能调用常成员函数. (4)非常量对象也可以调用常成员函数,但是如果有重载的非常成员函数则会调用非常成员函数. 重载看例子: #include<iostream> u

  • C++ 中const修饰虚函数实例详解

    C++ 中const修饰虚函数实例详解 [1]程序1 #include <iostream> using namespace std; class Base { public: virtual void print() const = 0; }; class Test : public Base { public: void print(); }; void Test::print() { cout << "Test::print()" << end

  • 浅谈C++ Explicit Constructors(显式构造函数)

    C++ 为类(Class)提供了许多默认函数.如果自己没有申明,编译器会为我们提供一个copy构造函数.一个copy assignment操作符和一个析构函数.此外,如果没有申明任何构造函数,编译器会为我们申明一个default构造函数.很像下面的Empty类: class Empty{ public: Empty(); Empty(const Empty &rhs); ~Empty(); Empty& operator=(const Empty &rhs); }; 就像Effec

  • C++ const修饰变量和修饰函数介绍

    const修饰变量 关于const最常见的一个面试题是这样的:char *const和const char*有什么区别,大家都知道const修饰符代表的是常量,即const修饰的变量一旦被初始化是不能被更改的,这两个类型一个代表的是指针不可变,一个代表指针指向内容不可变,但具体哪个对应哪个,很多人一直搞不清楚. 有这样一个规律,const修饰的是它前面所有的数据类型,如果const在最前面,那么把它和它后面第一个数据类行交换.比如上面的const char*交换之后就是char const *,

  • Kotlin语法学习-变量定义、函数扩展、Parcelable序列化等简单总结

    Kotlin语法学习-变量定义.函数扩展.Parcelable序列化等简单总结 今年 Google I/O 2017 开发者大会中,Google 宣布正式把 Kotlin 纳入 Android 程序的官方一级开发语言(First-class language),作为Android开发者,当然要逐步熟悉这门语言,第一步就要从语法开始学习. 在这之前,我们需要了解怎么使用Kotlin编写一个Android应用.对于Android Studio 3.0版本,我们在创建工程的时候直接勾选 Include

  • C++实操之内联成员函数介绍

    目录 前言 什么是内联函数: 如何使一个函数成为内联: 为什么使用内联: 优点 : 缺点 : 关键点 : 总结 前言 在C语言中,我们使用了宏函数,这是编译器用来减少执行时间的一种优化技术.那么问题来了,在C++中,有什么更好的方法来解决这个问题呢?我们引入了内联函数,这是编译器用来减少执行时间的一种优化技术.我们将讨论内联函数的 "what, why, when & how". 什么是内联函数: 内联函数是C++的一个增强功能,可以减少程序的执行时间.函数可以通过指示编译器,

  • C++中的函数介绍

    (一)函数使用规则 函数的定义不能嵌套但调用可以嵌套 在函数调用时,如某一默认参数要指明一个特定值,则有其之前所有参数都必须赋值 赋默认实参时 一旦某个形参被赋予了默认值,它后面的所有形参都必须有默认值,因为设置默认参数的顺序是自右向左:且注意默认值不可以是局部变量 函数参数的默认值可以是表达式 如果在函数定义时设置了默认参数,则就不能在函数声明时再次设置,反之亦然 函数只有一个 返回值,除void类型函数 函数调用可以出现在执行语句中,也可以出现在表达式中,甚至还可以作为一个函数的实参,但不可

  • JavaScript中Hoisting详解 (变量提升与函数声明提升)

    本文主要给大家介绍了关于JavaScript中Hoisting(变量提升与函数声明提升)的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 如何将 函数声明 / 变量 "移动" 到作用域的顶部. 术语 Hoisting(提升) 在很多 JavaScript 博文中被用来解释标识符的解析.其实 Hoisting(提升) 这个词是用来解释 变量 和 函数声明 是如何被提升到 函数或全局 作用域顶部的.你在任何的 JavaScript 文档中找不到这个术语,我们说的

  • JavaScript中变量提升和函数提升的详解

    第一篇文章中提到了变量的提升,所以今天就来介绍一下变量提升和函数提升.这个知识点可谓是老生常谈了,不过其中有些细节方面博主很想借此机会,好好总结一下. 今天主要介绍以下几点: 1. 变量提升 2. 函数提升 3. 为什么要进行提升 4. 最佳实践 那么,我们就开始进入主题吧. 1. 变量提升 通常JS引擎会在正式执行之前先进行一次预编译,在这个过程中,首先将变量声明及函数声明提升至当前作用域的顶端,然后进行接下来的处理.(注:当前流行的JS引擎大都对源码进行了编译,由于引擎的不同,编译形式也会有

  • javascript条件式访问属性和箭头函数介绍

    目录 一.条件式访问属性 二.箭头函数介绍 一.条件式访问属性 ?. 是ES2020引入的新特性,是一个条件式属性访问操作符,当你访问值为undefined变量的某个属性值时,如果使用.操作符会直接报错,如果使用条件式属性访问操作符来访问会返回undefined. 看例子: let book = {price:10, edition:10, name:"javascirpt" } console.log(book.page.num) 直接报错: TypeError: Cannot re

  • C++的静态成员变量和静态成员函数详解

    目录 一.static修饰变量 二.static修饰函数 三.static在类中使用 1.创建与初始化 2.使用问题 3.在public.private下static变量使用 四.class含有static变量所占空间 五.练习题:求学生总人数.总分.平均分系统. 总结 static int a = 10;//在静态区分配空间,不在堆栈 在静态区分配空间,不在堆栈分配空间.因此,只有等到所以函数全部执行完成后,才会释放空间. 一.static修饰变量 void text() { static i

  • 好用的C++ string Format“函数”介绍

    我这个人总是喜欢在写代码时追求极致,比如总是纠结于变量的命名,内存的消耗,执行的效率,接口的便捷性,代码的可扩展性...但很多时候需要在他们之间做取舍,这就导致我在编码时经常陷入僵局,唉...真是程序员的可悲,为此几年前我还专门将自己的CSDN签名改成了现在这样. 今天我又带来一个函数,相比网上其他版本效率更高(不存在额外拷贝问题),使用更便捷(无需预先分配缓存). 起初我设计的函数如下:相比网上其他的Format,特点是降低了内存消耗,也提升了使用的便捷性,但带来了执行效率的下降,而更严重的是

  • C++静态成员变量和静态成员函数的使用方法总结

    一.静态成员变量: 类体中的数据成员的声明前加上static关键字,该数据成员就成为了该类的静态数据成员.和其他数据成员一样,静态数据成员也遵守public/protected/private访问规则.同时,静态数据成员还具有以下特点: 1.静态数据成员的定义. 静态数据成员实际上是类域中的全局变量.所以,静态数据成员的定义(初始化)不应该被放在头文件中. 其定义方式与全局变量相同.举例如下: xxx.h文件 class base{ private: static const int _i;//

随机推荐