const那些事(代码片段)

ljwgis ljwgis     2022-11-30     256

关键词:

Const那些事

const对象默认为文件局部对象

注意:非const变量默认为extern。要使const变量能够在其他文件中访问,必须在文件中显示地指定它为extern。

未被const修饰的变量在不同文件的访问
//file1.cpp
int ext; //默认为extern
//file2.cpp
#include <iostream>
extern int ext;
int main()
	std::cout<<(ext+10)<<std::endl;

const常量在不同文件的访问
//file1.cpp
extern const int ext = 12;
//file2.cpp
#include <iostream>
extern const int ext;
int main()
	std::cout<<ext<<std::endl;

小结:可以发现未被const修饰的变量不需要extern显示声明!而const常量需要显示声明extern,并且需要初始化!因为常量在定义后就不能被修改,所以定义时必须初始化。

指针与const

与指针相关的const有四种:

const char *a; //指向const对象的指针或指向常量的指针
char const *a; //同上

char *const a; //指向类型对象的const指针(char型常量指针)
const char* const a;//指向char型常量的char型常量指针

小结:如果const位于的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;如果const位于的右侧,const就是修饰指针本身,即指针本身是常量。

具体使用如下:

(1)指向常量的指针

? 不能使用void*指针保存const对象的地址,必须用**const void ***类型的指针保存const对象的地址。

const int p = 10;
const void *vp = &p;
void *vp = &p; //error

? 允许把非const对象的地址赋给指向const对象的指针

const int *ptr;
int val = 3;
ptr = &val;

不能通过ptr指针来修改val的值,即使它指向的是非const对象。

不能使用指向const对象的指针修改其基础对象,然而如果该指针指向了非const对象,可以用其他方式修改其所指的对象。可以修改const指针所指向的值,但是不能通过const对象指针来进行修改

int *ptr1 = &val;
*ptr1 = 4;
cout<<*ptr<<endl;

小结:

? 对于指向常量的指针,不能通过指针来修改对象的值。也不能使用**void *指针保存const对象的地址,必须使用const void ***类型的指针保存const对象的地址。

? 允许把非const对象的地址赋值给const对象的指针,如果要修改指针所指向的对象值,必须通过其他方式修改,不能直接通过当前指针直接修改。

(2) 常量指针

const指针必须进行初始化,且const指针的值不能修改。

#include <iostream>
using namespace std;
int main()
	int num = 0;
	int *const ptr = &num; //const指针必须初始化,并且const指针的值不能修改
	int *t = &num; //通过修改非常量指针指向的对象,完成修改常量指针指向的值的目的
	*t = 1; //t指针指向num的地址,其指向的值(num)改为1
	cout<<*ptr<<endl;  //1

上述修改ptr指针所指向的值,可以通过非const指针来修改。

#include <iostream>
using namespace std;
int main()

	const int num = 0;
	int * const ptr = &num;  //error!const int * -> int *(ptr指向一个非常量)
    //若改为const int *ptr/const int * const ptr,可正常运行
	cout<<*ptr<<endl;

(3)指向常量的常指针

const int p = 3;
const int * const ptr = &p;

ptr是一个const指针,指向了一个int类型的const对象。

函数中使用const

const修饰函数的返回值

(1)const int

const int func1();

(2)const int *

const int * func2();

指针指向的内容不变(func2函数返回值是一个指针,指向一个常量)

(3)int *const

int *const func2();

指针本身不可变(func2函数返回一个int类型常量指针)

const修饰函数参数

(1)传递过来的参数及指针本身在函数内不可变,无意义!

void func(const int var);  //传递过来的参数不可变
void func(int *const var); //指针本身不可变

表明参数在函数体内不能被修改,此处var本身就是形参不会改变,没有意义;包括传入的形参是指针也是一样。输入参数采用值传递,由于函数将自动产生临时变量以用于复制该参数,该输入参数本来就无需保护,所以不要加const修饰。

(2)参数指针所指内容为常量不可变

void StringCopy(char *dst, const char *src)

其中src是输入参数,dst是输出参数。给src加上const修饰后,如果函数体内的语句试图改动src的内容,编译器将指出错误,这就是加了const的作用域之一。

(3)参数为引用,为了增加效率同时防止修改

void func(const A &a);

对于非内部数据类型的参数,像void func(A a)这样的声明函数注定效率比较低,因为函数体内将产生A类型的临时对象用于复制参数a,而临时对象的构造、复制、析构过程都将消耗时间。

为了提高效率,可将函数声明改为void func(A &a),因为引用传递仅借用参数别名,不产生临时对象,但它也有缺点:引用传递有可能改变参数a,这不是我门想要的,所以加const修饰。

问题:是否应将void func(int x) 改写为void func(const int &x),以便提高效率?

:完全没必要,因为内部数据类型的参数不存在构造、析构的过程,而复制也非常快,“值传递”和“引用传递”的效率几乎相当。

小结:对于非内部数据类型的输入参数,应该将“值传递”的方式改为“const 引用传递”,目的是提高效率;对于内部数据类型的输入参数,不要将“值传递”的方式改为“const 引用传递”。否则既达不到提高效率的目的,又降低了函数的可理解性。

类中使用const

在类中,任何不会修改数据成员的函数都应该声明为const类型。如果在编写const成员函数时,不慎修改数据成员,或者调用了其他非const成员函数,编译器将报错,这无疑会提高程序的健壮性。使用const关键字声明的成员函数,称为常成员函数,只有常成员函数才有资格操作常量或者常对象,没有使用const关键字声明的成员函数不能用来操作常对象。

对于类中的const成员变量必须通过列表初始化进行初始化。

class Apple

private:
	int people[100];
public:
	Apple(int i);  //构造函数声明
	const int apple_number; //const数据成员
;

Apple::Apple(int i)::apple_number(i)//构造函数定义,使用列表初始化



const对象只能访问const成员函数,而非const对象可以访问任意的成员函数,包括const成员函数。

//apple.cpp
class Apple

private:
    int people[100];
public:
    Apple(int i); 
    const int apple_number;
    void take(int num) const;
    int add(int num);
    int add(int num) const;
    int getCount() const;

;
//main.cpp
#include<iostream>
#include"apple.cpp"
using namespace std;

Apple::Apple(int i):apple_number(i)



int Apple::add(int num)
    take(num);

int Apple::add(int num) const
    take(num);

void Apple::take(int num) const

    cout<<"take func "<<num<<endl;

int Apple::getCount() const

    take(1);
//    add(); //error
    return apple_number;

int main()
    Apple a(2);
    cout<<a.getCount()<<endl;
    a.add(10);
    const Apple b(3);
    b.add(100);
    return 0;

//编译: g++ -o main main.cpp apple.cpp
//结果
take func 1
2
take func 10
take func 100

除了上述的初始化const常量初始化列表方式外,也可以通过下面方法:

一:将常量定义与static结合

static const int apple_number

二:在外面初始化

const int Apple::apple_number=10;

三:如果你使用C++11进行编译,直接可以在定义处初始化

static const int apple_number=10;
//or
const int apple_number=10;

这里提到了static,下面简单的说一下:在C++中,static静态成员变量不能在类的内部初始化在类的内部只是声明,定义必须在类的外部,通常在类的实现文件中初始化。

static int ap;  //在类中声明
int Apple::ap=666 //在类实现文件中使用

《c专家编程》---不知道的那些事(代码片段)

1.char*b=constchar*a会报警告,而constchar*a=char*b不会,要使这种赋值形式合法,必须满足下列条件之一:  1)两个操作数都是指向有限定符或无限定符的相容类型的指针  2)左边指针指向的类型必须具有右边指针所指向类型的... 查看详情

异常的那些事(代码片段)

使用traceback获取详细的异常信息try:1/0exceptException,e:printe结果:integerdivisionormodulobyzero只知道是报了这个错,但是却不知道在哪个文件哪个函数哪一行报的错。 下面使用traceback模块importtracebacktry:1/0exceptException,e:traceback.print_exc(... 查看详情

闭包那些事(代码片段)

定义:在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)。 例子: 1defmake_adder(addend):2defadder(augend):3returnaugend+addend4returnadder6p=make_adder(23)7q=make_adder(44)89p... 查看详情

xampp那些事(代码片段)

xampp依赖库https://www.microsoft.com/zh-CN/download/details.aspx?id=29下载地址https://www.apachefriends.org/zh_cn/download.htmlxampp数据库配置修改注意事项Composer官网https://getcomposer.org/download/Composer安装注意事项D:xamp 查看详情

static那些事(代码片段)

static那些事当与不同类型一起使用时,static关键词具有不同的含义。静态变量:函数中的变量、类中的变量静态类的成员:类对象和类中的函数静态变量函数中的静态变量当变量声明为static时,空间将在程序的生命周期内分配。... 查看详情

关于android性能监控matrix那些事?你知道那些?(完)(代码片段)

关于Android性能监控Matrix那些事?你知道那些?(上)关于Android性能监控Matrix那些事?你知道那些(中)?视频也更新了:微信Matrix卡顿监控实战,函数自动埋点监控方案今天抽空把后面的... 查看详情

this指针那些事(代码片段)

this指针那些事引言? 对于Python来说有self,类比到C++中就是this指针用处一个对象的this指针并不是对象本身的一部分,不会影响sizeof(对象)的结果。this的作用域是在类内部,当在类的非静态成员函数中访问类的非静态成员时,编译... 查看详情

反射那些事(代码片段)

一直以为只要把类的成员变量设置为private,或者方法设置为private,那么他就对外完全隐藏,类外部无法直接对该成员变量或者方法进行直接访问。但是java的反射,拥有十分强大的功能,它可以访问类中的任意成员变量和方法,... 查看详情

线段树那些事(代码片段)

线段树是学不明白了……部分指针用法对于这段代码,structNodeinta,b,c;YJH[100],x;Node*p=YJH,*q=&x;以下代码在使用过程中是等价的:cout<<x.a<<endl;cout<<q->a<<endl;cout<<(*q).a<<endl;cout<<YJH[2 查看详情

关于网络超时时间那些事(代码片段)

文章目录一、connectTimeout应用层的超时分析内核层的超时分析综合分析二、writeTimeout三、readTimeout四、httpClient中的connectTimeout、socketTimeout、connectionRequestTimeout区别五、一些额外知识点一些资料在实际编程中,我们会经常到超... 查看详情

js属性的那些事(代码片段)

js中一切皆对象,而对象,本质上是一系列属性的集合.对象的属性可分为:命名属性:可直接通过“.”访问到的属性数据属性:专门保存一个值的属性访问器属性:保护数据属性的特殊属性内部属性:不能通过“.”直接访问的属性(比如... 查看详情

elasticsearch有关查询的那些事(代码片段)

ElasticSearch有关查询的那些事上一篇文章介绍了一下ElasticSearch的一些基础的索引,文档的CRUD方法,接下来介绍一些花式查询的操作修改在说查询之前先补充一下之前没讲到的修改功能的内容全量修改现在先重新创建一个... 查看详情

samesite那些事(代码片段)

在《Web安全漏洞之CSRF》中我们了解到,CSRF的本质实际上是利用了Cookie会自动在请求中携带的特性,诱使用户在第三方站点发起请求的行为。除了文中说的一些解决方式之外,标准还专门为Cookie增加了SameSite属性,用来规避该问... 查看详情

关于thisstate的那些事(代码片段)

1.state的定义  状态(state)和属性(props)类似,都是一个组件所需要的一些数据集合,但是它是私有的,并且由组件本身完全控制,可以认为它是组件的“私有属性(或者是局部属性)”。2.thisState的三件事  1.不要... 查看详情

关于android性能监控matrix那些事?你知道那些(中)?(代码片段)

昨天更新了关于Android性能监控Matrix那些事?你知道那些(上)?说的的视频也更新了:微信Matrix卡顿监控实战,函数自动埋点监控方案今天我们接着聊下文:4.Hprof文件分析5.卡顿监控6.卡顿监控源码解析7.插... 查看详情

使用分享hive分区表那些事(代码片段)

一、静态分区1.创建静态分区格式:createtableemployees(namestring,salaryfloat,subordinatedarray<string>,deductionsmap<string,float>,addressstruct<street:string,city:string,state:string,zip:int>)parti 查看详情

二进制那些事(代码片段)

...了计算机的信息只能用二进制数处理。本期将介绍二进制那些事。移位运算移位运算指的是将二进制数值的各数位进行左右移位的运算。左移空出来的低位要进行补0操作,右移空出来的高位要进行怎样的操作,我们会在后面说... 查看详情

bind的那些事(代码片段)

最近面头条的时候,要求自己手动实现一个bind函数,然后又问了bind还能干嘛。这里就围绕这两个好好写一下。首先bind的文档说明:bind()方法创建一个新的函数,当被调用时,将其this关键字设置为提供的值,在调用新函数时,在... 查看详情