const_用法总结(C++)

时间:2024.5.4

const用法总结(C++)

一、关于一般常量

声明或定义的格式如下:

const 类型 名 = 常量或常量表达式;/类型 const 名 = 常量或常量表达式;

两种定义是完全等价的,如:const int i=10;/int const i=10;

没有必要出那么多的乱定义的方式,只需规范定义即可,const int i=128;/int const i=128; *因为常量在定义后就不能被修改,所以定义时必须初始化。

*非const变量默认为extern。

*const 对象默认为文件的局部变量,要使const变量能够在其他的文件中也能访问,必须显式地指定它为extern(另:链接制定),即扩大了作用域。

例如:

const int bufSize = 512; // 作用域只限于定义此变量的文件

extern const int bufSize = 512; // extern用于扩大作用域,作用域为整个源程序(只有extern

位于函数外部时,才可以含有初始化式)

二、关于数组及结构体

声明或定义的格式如下:

const 类型 名[]={};/类型 const 名[]={};

两种定义是完全等价的,如:const int A[] = {1,2,3,4,5};/int const A[] = {1,2,3,4,5}; struct SI {int i1,i2;};

const SI s[] = {{1,2},{3,4}};

//上面的数组和结构体的两个const都是变量集合,编译器会为其分配内存,所以不能在编译期间使用其中的值(如:int temp[A[2]],这样的话编译器会报告不能找到常量表达式)。

三、关于引用

声明或定义的格式如下:

const 类型 &名 = 已定义并初始化的变量/常量;/类型 const &名 =已定义并初始化的变量/常量;

两种定义是完全等价的,如:

const int i = 128;

const int &r = i;/int const &r = i;

*const引用就是指向const对象的引用。

*普通引用不能绑定到const对象,但const引用可以绑定到非const对象。如:

const int i = 123; int j = 456;->

int &r=j;const int &r = j/i;

*非const 引用只能绑定到与该引用同类型的对象。

const 引用则可以绑定到不同但相关的类型的对象或绑定到右值。

例如:

1.const int &r = 100; // 绑定到字面值常量

2.int i = 50;

const int &r2 = r + i; // 引用r绑定到右值

3.double dVal = 3.1415;

const int &ri = dVal; // 整型引用绑定到double 类型

编译器会把以上代码转换成如下形式的编码:

int temp = dVal; // create temporary int from double

const int &ri = temp; // bind ri to that temporary

个人理解:普通引用只能绑定同类型的普通对象;但const引用可以绑定相关类型的任何对象,可以是const对象,也可以是非const对象,且绑定的对象可以用操作符连接;

四、关于指针

1.指向const对象的指针(指针所指向的内容为常量)

声明或定义的格式如下(定义时可以不初始化):

const 类型 *名=&名;/类型 const *名=&名;

两种定义是完全等价的,如:

const int i = 100;

const int *p = &i;/int const *p = &i;(p是指向int 类型的const 对象的指针)

*也允许把非const 对象的地址赋给指向const 对象的指针。

*不能使用指向const 对象的指针修改基础对象。

*如何将一个const 对象合法地赋给一个普通指针???强制转换(const_cast<普通指针类型>*(&已初始化的变量))。如:

const double i = 3.14;

double *p = const_cast<double*>(&i);

*const_cast是C++中标准的强制转换,C语言使用(double*)&i。

个人理解:被const修饰的变量的赋值不可以改变,因为变量的赋值是常量,然指向const对象的指针的赋值却可以改变,因为指针是变量,且未被const直接(就是const最近修饰的)修饰。

2.const指针(指针本身为常量)

声明或定义的格式如下(定义时必须初始化):

类型 *const 名 = &名,如:

int i = 0;

int j = 10;

int *const p = &i;(p是指向int型对象的const指针)

指针的指向不能被修改,p = &j; // error

指针指向的基础对象可以修改,*p = 1; // ok,即没有被const修饰的变量i可以被修改

个人理解:被const修饰的指针的赋值是不可以改变的,因为指针本身就是常量,然未被const修饰的变量却可以。

3.指向const对象的const指针(指针本身和指向的内容均为常量)

声明或定义的格式如下(定义时必须初始化):

const 类型 *const 名 = ……

例如:

const double pi = 3.14159;

const double i = 3.14;

const double *const ptr = &pi;(ptr是指向double类型的const对象的const指针) 指针的指向不能被修改,ptr = &i; // error

指针所指向的基础对象也不能被修改,*ptr = i; // error

个人理解:被const修饰的指针的赋值是不可以改变的,因为指针本身就是常量,然被const修饰的变量也不可以,因为变量的赋值是常量。

五、关于一般函数

1.修饰函数的参数

class Test;

void func1(const int i); //i不能被修改

void func3 (const Test &r); //r所引用的对象不能被修改

void func2 (const char *p); //p所指向的内容不能被修改

2.修饰函数的返回值

返回值:const int func1();

此处返回int 类型的const值,意思指返回原函数里的变量的初值不能被修改,但是函数按值返回的这个变量被制成副本,能不能被修改就没有了意义,它可以被赋给任何const或非const类型变量,完全不需要加上这个const关键字。

[*注意*]但这只对于内部类型而言(因为内部类型返回的肯定是一个值,而不会返回一个变量,不会作为左值使用,否则编译器会报错),对于用户自定义类型,返回值是常量是非常重要的(后面在类里面会谈到)。

返回引用:const int &func2();

注意:千万不要返回局部对象的引用,否则会报运行时错误,因为一旦函数结束,局部对象被释放,函数返回值指向了一个对程序来说不再有效的内存空间。

返回指针:const int *func3();

注意:千万不要返回指向局部对象的指针,因为一旦函数结束,局部对象被释放,返回的指针变成了指向一个不再存在的对象的悬垂指针。

六、关于类

class A

{

public:

void func();

void func() const;

const A operator+(const A &) const;

private:

int num1;

mutable int num2;

const size_t size;

};

1.修饰成员变量

const size_t size;

对于const的成员变量:1.必须在构造函数里面进行初始化;2.只能通过初始化成员列表来初始化;3.试图在构造函数体内对const成员变量进行初始化会引起编译错误,如:

A::A(size_t sz):size(sz){} //ok:使用初始化成员列表来初始化

A::A(size_t sz)

2.修饰类成员函数

void func() const; // const成员函数中不允许对数据成员进行修改,如果修改,编译器将报错。如果某成员函数不需要对数据成员进行修改,最好将其声明为const 成员函数,这将大大提高程序的健壮性。

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

class A

{

public:

void func(); // [1]:一个函数

void func() const; // [2]:上一个函数[1]的重载

……

};

A a(10);

a.func(); // 调用函数[1]

const A b(100);

b.func(); // 调用函数[2]

如何在const成员函数中对成员变量进行修改???

下面提供几种方式(只提倡使用第一种,其他方式不建议使用)

(1)标准方式:mutable(const的反义词)

class A

{

public:

A::A(int i):m_data(i){}

void SetValue(int i){ m_data = i; }

private:

mutable int m_data; // 这里处理

};

个人理解: 类的成员函数不会改变对象的状态,那么这个成员函数一般会声明成const的,但,有些时候,我们需要在const的函数里面修改一些跟类状态无关的数据成员,那么这个数据成员就应该被mutalbe来修饰。

(2)强制转换:static_cast

class A

{

public:

A::A(int i):m_data(i){}

void SetValue(int i)

{ static_cast<int>(m_data) = i; } // 这里处理

private:

int m_data;

};

(3)强制转换:const_cast

class A

{

public:

A::A(int i):m_data(i){}

void SetValue(int i)

{ const_cast<A*>(this)->m_data = i; } // 这里处理

private:

int m_data;

};

(4)使用指针:int *

class A

{

public:

A::A(int i):m_data(i){}

void SetValue(int i)

{ *m_data = i; } // 这里处理

private:

int *m_data;

};

(5)未定义的处理方式

class A

{

public:

A::A(int i):m_data(i){}

void SetValue(int i)

{ int *p = (int*)&m_data; *p = i } // 这里处理

private:

int m_data;

};

注意:这里虽然说可以修改,但结果是未定义的,避免使用!

3.修饰类对象

const A::a;

类对象a只能调用const成员函数,否则编译器报错。

4.修饰类成员函数的返回值

const A operator+(const A &) const;

前一个const 用来修饰重载函数operator+的返回值,可防止返回值作为左值进行赋值操作。

七、使用const的一些建议

1.要大胆的使用const,这将给你带来无尽的益处,但前提是你必须搞清楚原委;

2.要避免最一般的赋值操作错误,如将const变量赋值,具体可见思考题;

3.在参数中使用const应该使用引用或指针,而不是一般的对象实例,原因同上;

4.const在成员函数中的三种用法(参数、返回值、函数)要很好的使用;

5.不要轻易的将函数的返回值类型定为const;

6.除了重载操作符外一般不要将返回值类型定为对某个对象的const引用;

个人理解:要谨慎避免const的低级错误。

八、cons有什么主要的作用?

1.可以定义const常量,具有不可变性。

例如:

const int Max=100;

int Array[Max];

2.便于进行类型检查,使编译器对处理内容有更多了解,消除了一些隐患。

例如:

void f(const int i) { .........}

编译器就会知道i是一个常量,不允许修改;

3.可以避免意义模糊的数字出现,同样可以很方便地进行参数的调整和修改。

同宏定义一样,可以做到不变则已,一变都变!如(1)中,如果想修改Max的内容,只需要:const int Max=you want;即可!

4.可以保护被修饰的东西,防止意外的修改,增强程序的健壮性。

还是上面的例子,如果在函数体内修改了i,编译器就会报错;

例如:

void f(const int i) { i=10;//error! }

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

class A

{

......

void f(int i) {......} file://一个函数

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

......

};

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

例如:

#define PI 3.14159 file://常量宏

const doulbe Pi=3.14159; file://此时并未将Pi放入ROM中

......

double i=Pi; file://此时为Pi分配内存,以后不再分配!

double I=PI; file://编译期间进行宏替换,分配内存

double j=Pi; file://没有内存分配

double J=PI; file://再进行宏替换,又一次分配内存!

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

个人理解:const修饰的常量更有利于节省内存,只要首次分配了内存,则之后不再必要分配内存。

7.提高了效率。

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

个人理解:const常量也节省了存储空间。


第二篇:const 用法总结(C++)档


const 用法总结(C++)

根据个人的学习和理解,下面我将从以下几个分类来进行讨论,如有错误之处,还请各位大虾多多指教!(部分内容直接转载,以供学习和参考)

一、关于一般常量

声明或定义的格式如下:

const <类型说明符> <变量名> = <常量或常量表达式>; [1]

<类型说明符> const <变量名> = <常量或常量表达式>; [2]

[1]和[2]的定义是完全等价的。

例如:

整形int(或其他内置类型:float,double,char)

const int bufSize = 512;

或者

int const bufSize = 512;

因为常量在定义后就不能被修改,所以定义时必须初始化。

bufSize = 128; // error:attempt to write to const object

const string cntStr = "hello!"; // ok:initialized

const i, j = 0; // error: i is uninitialized const

非const变量默认为extern。

const 对象默认为文件的局部变量。要使const变量能够在其他的文件中访问,必须显式地指定它为extern。

例如:

const int bufSize = 512; // 作用域只限于定义此变量的文件

extern const int bufSize = 512; // extern用于扩大作用域,作用域为整个源程序(只有extern 位于函数外部时,才可以含有初始化式)

二、关于数组及结构体

声明或定义的格式如下:

const <类型说明符> <数组名>[<大小>]…… [1]

<类型说明符> const <数组名>[<大小>]…… [2]

[1]和[2]的定义是完全等价的。

例如:

整形int(或其他内置类型:float,double,char)

const int cntIntArr[] = {1,2,3,4,5};

或者

int const cntIntArr[] = {1,2,3,4,5};

struct SI

{

int i1;

int i2;

};

const SI s[] = {{1,2},{3,4}};

// 上面的两个const都是变量集合,编译器会为其分配内存,所以不能在编译期间使用其中的值(例如:int temp[cntIntArr[2]],这样的话编译器会报告不能找到常量表达式)

三、关于引用

声明或定义的格式如下:

const <类型说明符> &<变量名> = …… [1]

<类型说明符> const &<变量名> = …… [2]

[1]和[2]的定义是完全等价的。

例如:

const int i = 128;

const int &r = i;(或者 int const &r = i;)

const 引用就是指向const 对象的引用。

普通引用不能绑定到const 对象,但const 引用可以绑定到非const 对象。

const int ii = 456;

int &rii = ii; // error

int jj = 123;

const int &rjj = jj; // ok

非const 引用只能绑定到与该引用同类型的对象。

const 引用则可以绑定到不同但相关的类型的对象或绑定到右值。

例如:

1.const int &r = 100; // 绑定到字面值常量

2.int i = 50;

const int &r2 = r + i; // 引用r绑定到右值

3.double dVal = 3.1415;

const int &ri = dVal; // 整型引用绑定到double 类型

编译器会把以上代码转换成如下形式的编码:

int temp = dVal; // create temporary int from double

const int &ri = temp; // bind ri to that temporary

四、关于指针

1.指向const 对象的指针(指针所指向的内容为常量)

声明或定义的格式如下(定义时可以不初始化):

const <类型说明符> *<变量名> …… [1]

<类型说明符> const *<变量名> …… [2]

[1]和[2]的定义是完全等价的。

例如:

const int i = 100;

const int *cptr = &i;

或者

int const *cptr = &i; [cptr 是指向int 类型的const 对象的指针]

允许把非const 对象的地址赋给指向const 对象的指针,例如:

double dVal = 3.14; // dVal is a double; its value can be change const double *cdptr = &dVal; // ok;but can't change dVal through cdptr

不能使用指向const 对象的指针修改基础对象。然而如果该指针指向的是一个没const 对象(如cdptr),可用其他方法修改其所指向的对象。

如何将一个const 对象合法地赋给一个普通指针???

例如:

const double dVal = 3.14;

double *ptr = &dVal; // error

double *ptr = const_cast<double*>(&dVal);

// ok: const_cast是C++中标准的强制转换,C语言使用:double *ptr = (double*)&dVal;

2.const 指针(指针本身为常量)

声明或定义的格式如下(定义时必须初始化):

<类型说明符> *const <变量名> = ……

例如:

int errNumb = 0;

int iVal = 10;

int *const curErr = &errNumb; [curErr 是指向int 型对象的const 指针]

指针的指向不能被修改。

curErr = &iVal; // error: curErr is const

指针所指向的基础对象可以修改。

*curErr = 1; // ok:reset value of the object(errNumb) which curErr is bind

3.指向const 对象的const 指针(指针本身和指向的内容均为常量)

声明或定义的格式如下(定义时必须初始化):

const <类型说明符> *const <变量名> = ……

例如:

const double pi = 3.14159;

const double dVal = 3.14;

const double *const pi_ptr = &pi; [pi_ptr 是指向double 类型的const 对象的const 指针]

指针的指向不能被修改。

pi_ptr = &dVal; // error: pi_ptr is const

指针所指向的基础对象也不能被修改。

*pi_ptr = dVal; // error: pi is const

五、关于一般函数

1.修饰函数的参数

class A;

void func1(const int i); // i不能被修改

void func3 (const A &rA); // rA所引用的对象不能被修改

void func2 (const char *pstr); // pstr所指向的内容不能被修改

2.修饰函数的返回值

返回值:const int func1(); // 此处返回int 类型的const值,意思指返回的原函数里的变量的初值不能被修改,但是函数按值返回的这个变量被制成副本,能不能被修改就没有了意义,它可以被赋给任何的const或非const类型变量,完全不需要加上这个const关键字。

[*注意*]但这只对于内部类型而言(因为内部类型返回的肯定是一个值,而不会返回一个变量,不会作为左值使用,否则编译器会报错),对于用户自定义类型,返回值是常量是非常重要的(后面在类里面会谈到)。

返回引用:const int &func2(); // 注意千万不要返回局部对象的引用,否则会报运行时错误:因为一旦函数结束,局部对象被释放,函数返回值指向了一个对程序来说不再有效的内存空间。 返回指针:const int *func3(); // 注意千万不要返回指向局部对象的指针,因为一旦函数结束,局部对象被释放,返回的指针变成了指向一个不再存在的对象的悬垂指针。

六、关于类

class A

{

public:

void func();

void func() const;

const A operator+(const A &) const;

private:

int num1;

mutable int num2;

const size_t size;

};

1.修饰成员变量

const size_t size; // 对于const的成员变量,[1]必须在构造函数里面进行初始化;[2]只能通过初始化成员列表来初始化;[3]试图在构造函数体内对const成员变量进行初始化会引起编译错误。

例如:

A::A(size_t sz):size(sz) // ok:使用初始化成员列表来初始化

{

}

A::A(size_t sz)

2.修饰类成员函数

void func() const; // const成员函数中不允许对数据成员进行修改,如果修改,编译器将报错。如果某成员函数不需要对数据成员进行修改,最好将其声明为const 成员函数,这将大大提高程序的健壮性。

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

class A

{

public:

void func(); // [1]:一个函数

void func() const; // [2]:上一个函数[1]的重载

……

};

A a(10);

a.func(); // 调用函数[1]

const A b(100);

b.func(); // 调用函数[2]

如何在const成员函数中对成员变量进行修改???

下面提供几种方式(只提倡使用第一种,其他方式不建议使用)

(1)标准方式:mutable

class A

{

public:

A::A(int i):m_data(i){}

void SetValue(int i){ m_data = i; }

private:

mutable int m_data; // 这里处理

};

(2)强制转换:static_cast

class A

{

public:

A::A(int i):m_data(i){}

void SetValue(int i)

{ static_cast<int>(m_data) = i; } // 这里处理 private:

int m_data;

};

(3)强制转换:const_cast

class A

{

public:

A::A(int i):m_data(i){}

void SetValue(int i)

{ const_cast<A*>(this)->m_data = i; } // 这里处理 private:

int m_data;

};

(4)使用指针:int *

class A

{

public:

A::A(int i):m_data(i){}

void SetValue(int i)

{ *m_data = i; } // 这里处理

private:

int *m_data;

};

(5)未定义的处理方式

class A

{

public:

A::A(int i):m_data(i){}

void SetValue(int i)

{ int *p = (int*)&m_data; *p = i } // 这里处理

private:

int m_data;

};

注意:这里虽然说可以修改,但结果是未定义的,避免使用!

3.修饰类对象

const A a; // 类对象a 只能调用const 成员函数,否则编译器报错。

4.修饰类成员函数的返回值

const A operator+(const A &) const; // 前一个const 用来修饰重载函数operator+的返回值,可防止返回值作为左值进行赋值操作。

例如:

A a;

A b;

A c;

a + b = c; // errro: 如果在没有const 修饰返回值的情况下,编译器不会报错。

七、使用const的一些建议

1.要大胆的使用const,这将给你带来无尽的益处,但前提是你必须搞清楚原委;

2.要避免最一般的赋值操作错误,如将const变量赋值,具体可见思考题;

3.在参数中使用const应该使用引用或指针,而不是一般的对象实例,原因同上;

4.const在成员函数中的三种用法(参数、返回值、函数)要很好的使用;

5.不要轻易的将函数的返回值类型定为const;

6.除了重载操作符外一般不要将返回值类型定为对某个对象的const引用;

八、cons有什么主要的作用?

1.可以定义const常量,具有不可变性。

例如:

const int Max=100;

int Array[Max];

2.便于进行类型检查,使编译器对处理内容有更多了解,消除了一些隐患。

例如:

void f(const int i) { .........}

编译器就会知道i是一个常量,不允许修改;

3.可以避免意义模糊的数字出现,同样可以很方便地进行参数的调整和修改。

同宏定义一样,可以做到不变则已,一变都变!如(1)中,如果想修改Max的内容,只需要:const int Max=you want;即可!

4.可以保护被修饰的东西,防止意外的修改,增强程序的健壮性。

还是上面的例子,如果在函数体内修改了i,编译器就会报错;

例如:

void f(const int i) { i=10;//error! }

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

class A

{

......

void f(int i) {......} file://一个函数

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

......

};

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

例如:

#define PI 3.14159 file://常量宏

const doulbe Pi=3.14159; file://此时并未将Pi放入ROM中

......

double i=Pi; file://此时为Pi分配内存,以后不再分配!

double I=PI; file://编译期间进行宏替换,分配内存

double j=Pi; file://没有内存分配

double J=PI; file://再进行宏替换,又一次分配内存!

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

7.提高了效率。

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

{

size = sz; // error:试图在构造函数体内对const成员变量进行初始化

}

【来源:/awacsljt/blog/item/91a7b312b6a9170b5baf5334.html】

更多相关推荐:
c&c++中const用法总结

const类型定义:指明变量或对象的值是不能被更新,引入目的是为了取代预编译指令**************常量必须被初始化*************************cons的作用(1)可以定义cons…

const用法总结

const看到const关键字很多程序员想到的可能是const常量这可有点象踩到陷井上还不知道自己危险了读读以下文字会使你对c中的const有一个全面的认识const是C中常用的类型修饰符有某些微妙的应用场合如...

C++中const用法总结

C中const用法总结作者JuKevin1const修饰普通变量和指针const修饰变量一般有两种写法constTYPEvalueTYPEconstvalue这两种写法在本质上是一样的它的含义是const修饰的...

c++const用法小结

C中const的用法小结来源本站原创编辑本站编辑时间20xx09241const常量如constintmax100优点const常量有数据类型而宏常量没有数据类型编译器可以对前者进行类型安全检查而对后者只进行字...

C++中const用法总结

C中const用法总结思维方式是什么为什么怎么用C中有些什么东西const可以修饰些什么什么原理谁变谁不变有什么好处C中有些什么数据变量常量字面量函数方法代码块常量101aabc先不讨论const定义的常量变量...

C++中const用法总结

2指针使用CONST1指针本身是常量不可变charconstpContentconstcharpContent2指针所指向的内容是常量不可变constcharpContentcharconstpContent3...

C++中const用法总结

C中const用法总结月光林地博客园1const修饰普通变量和指针const修饰变量一般有两种写法constTYPEvalueTYPEconstvalue这两种写法在本质上是一样的它的含义是const修饰的类型...

C++语言中const关键字用法总结

C语言中const关键字用法总结一const是什么在CC语言中const关键字是一种修饰符所谓修饰符就是在编译器进行编译的过程中给编译器一些要求或提示但修饰符本身并不产生任何实际代码就const修饰符而言它用来...

Const的用法大全

详解Const的用法SunnymanConst限定符主要是声明变量为只读它的用法我归纳学习了一下主要表现在以下几个方面1限定符声明变量只能被读constinti3声明i为一个只读变量但i不是常量而且这个变量必须...

const用法

使用const提高函数的健壮性看到const关键字C程序员首先想到的可能是const常量这可不是良好的条件反射如果只知道用const定义常量那么相当于把火药仅用于制作鞭炮const更大的魅力是它可以修饰函数的参...

const用法详解

const用法详解转面向对象是C的重要特性但是c在c的基础上新增加的几点优化也是很耀眼的就const直接可以取代c中的define以下几点很重要学不好后果也也很严重const1限定符声明变量只能被读consti...

Const用法

const用法详解面向对象是C的重要特性但是c在c的基础上新增加的几点优化也是很耀眼的就const直接可以取代c中的define以下几点很重要学不好后果也也很严重const1限定符声明变量只能被读constin...

const用法总结(44篇)