"const T " VS "T const " VS const 作用汇总

声明符:

这是第一个观点:

CC++的每一个声明都有两个主要的部分:一串0个或多个声明修饰符+一串0个或多个声明符(多个申明符用逗号分开)例如:

   Static unsigned long int         *x[N];

Declarationg specifier )(declarator

声明符就是要声明的名字,经常与像*,[],()&((在C++)组合在一起。在声明符中这个符号*意味着“指向”,[]意思是“数组”。因此,*x[N]是一个声明符说明x是一个有N个指针元素组成的数组,类型是在类型修饰符中指定的类型。例如,

Static unsigned long int *x[N];

x声明为这种类型的对象:“N指向无符号长整型元素组成的数组。“

我怎么知道*x[N]是一个指针数组而不是指向数组的指针呢?

它遵循这个原则:在声明符组中操作符的优先级与他们在表达式中的一致。

例如:[]*的优先级高。因此,在这个声明符中*x[N]意味着x 首先是一个数组,然后才是它的元素是一个指针。


圆括号:();在声明符中有两个作用:

一是作为函数调用操作符;

二是分组。


作为函数调用操作符时,()与[]的优先级相同,分组时()拥有最高的优先级。

例如,*f(int)是一个声明符,指定f是一个返回指针类型的函数。而(*f)(int)指定f是指向一个函数的函数指针。

声明符可能包含不止一个标识符。这个声明符*x[N]包含两个标识符,xN

只有一个标识符是被声明的,被称为声明ID。其他的,如果还有的话,必须似乎在之前声明的了。例如在这个声明符中x是声明ID


声明限定符

一些声明限定符可以是类型限定符诸如int,unsigned或者是一个新类型的标识符。他们也可以使存储类限定符像extern或者static。在C++中他们也可以是函数限定符像inline或者virtual


下面是另一个观点:

类型限定符作用于声明符ID的类型,其他的限定符提供非类型信息,这些信息直接作用于声明ID

例如:static unsigned long int *x[N]

声明x为一个变量类型:“由N个指向无符号长整型的指针组成的数组。“ ;关键字static限定x为静态分配的内存。


下面是另一个重要的观点:

声明限定符在声明中的顺序是无关紧要的。例如:

Const VP vectorTable[]

等价于

VP const vetorTable[]

const void* vetorTable[]

等价于

void const* vetorTable[]

我们大多数人将诸如static这样的存储类限定符(最左边)作为第一个声明限定符,但是这只是一个惯例,不是语言本身的要求。

声明限定符constvolatile是不同的:唯一的声明限定符也能出现在声明符中的是constvolatile

例如:在void*const vectorTable[]中的const出现在了声明符中。

在这中情况下,你就不能重新组织关键字的顺序,例如:*const void vetorTable[]是错误的。


 对于编译器来说声明限定符的顺序是无关紧要的。于是这两种声明是等价的:

const void *vetorTable[]; 

void const *vectorTable[];

几乎所有的CC++编程者都倾向于将constvolatile写在类型限定符的左边。我更喜欢将他们写在右边,并且我强烈推荐写在后边的这种写法。

尽管一般CC++是从左到右, 从上到下读的,读指针声明的时候,在某种意义上说,是相反的。也就是说,指针声明是从右到左读的。

通过将const置于其他类型限定符的右边,你可以严格的从右到左读指针声明,并且将const出现在右边的位置。

例如:

T const *p;

<------------

p声明为指向cons  T 的指针;

并且:

T *const p;

<------------

p声明为指向Tconst指针

const写在其他声明限定符之后实际上使得更加容易看到consttypedef结合的效果。

Typedef void*  VP;

Const VP  vectorTable[];

一种转化是象下面这样置换VP

Const (VP )vectorTable[]

Const(void*)vetorTable[]

使得它看起来vectorTable具有这种类型“指向const  void 的指针数组“,这是错误的

正确的转换是将VP置换为:

const  (VP) vectorTable[]

(void *)const vectorTable[]

也就是说,vectorTablel是指向voidconst指针数组,但是它却不是显然的。

const写在声明限定符的最右边使得更容易看到正确的翻译,

(VP) const vectorTable[];

(void *)const vectorTable[];

现在我意识到我正在推荐一种其他人很少用的风格,其他人都会将const放在左边;

但是,鉴于很少有CC++的程序员知道在声明中使用const时自己在做什么,每个人都不这样做是支持现在流行风格。为什么不抵制这种趋势。尝试着使用一种更加清晰的风格呢?

只要我还从事着这个职业,我就会一如既往的支持这种风格。尽管这对大多数程序员还没有任何影响,但是很多人还是养成了书写的坏习惯。

Const int  *p;(更加规范化)

而不是

Constint*  p;

也就是说,他们将空格和*作为声明限定符而不是声明符,我真的相信程序员这样书写给他们自己和其他人造成麻烦。

当然,空格对编译器毫无影响,但是将空格置于*之后会给人关于声明的内在结构造成一种错误的印象。


---------------------------------------------------------------------------------------------------------

const的作用 

const是C语言的一种关键字,起受保护,防止以外的变动的作用!可以修饰变量,参数,返回值, 函数体。

const可以提高程序的健壮性,你只管用到你想用的任何地方。


(一)const修饰参数。const只能修饰输入参数。
1、如果输入参数是指针型的,用const修饰可以防止指针被意外修改。
2、如果参数采用值传递的方式,无需const,因为函数自动产生临时变量复制该参数。

3、非内部数据类型的参数,需要临时对象复制参数,而临时对象的构造,析构,复制较为费时,因此建议采用前加const的引用方式传递非内部数据类型。而内部数据类型无需引用传递。


(二)const修饰函数返回值
1、函数返回const指针,表示该指针不能被改动,只能把该指针赋给const修饰的同类型指针变量。
2、函数返回值为值传递,函数会把返回值赋给外部临时变量,用const无意义!不管是内部还是非内部数据类型。

3、函数采用引用方式返回的场合不多,只出现在类的赋值函数中,目的是为了实现链式表达。


(三)const修饰C++成员函数。任何不修改数据成员的函数都应该声明为const类型,如果const成员函数修改了数据成员或者调用了其他函数修改数据成员,编译器都将报错!
class stack
{
	public:
		int GetCount(void) const ;
	private:
		int m_num;
};

int stack::GetCount(void) const
{
	m_num++;
}

编译器输出错误信息:error C2166: l-value specifies const object。


(四)const 修饰变量,表示该变量不能被修改。
1、const char *p 表示 指向的内容不能改变
2、char * const p,就是将P声明为常指针,它的地址不能改变,是固定的,但是它的内容可以改变。
3、这种const指针是前两种的结合,使得指向的内容和地址都不能发生变化.
const double pi = 3.14159;

const double *const pi_ptr = &pi;


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值