Thursday, March 24, 2016

const C/C++ Keyword

const在C语言中算是一个比较新的描述符,我们称之为常量修饰符,即就是说其所修饰的对象为常量。当你代码中想要设法阻止一个变量被改变,那么这个时候可以选择使用const关键字。在你给一个变量加上const修饰符的同时,通常需要对它进行初始化,在之后的程序中就不能再去改变它。
可能有的人会有一个疑问,我们不是有在C中有预处理指令#define VariableName VariableValue 可以很方便地进行值替代,干嘛还要引入const修饰符呢?!这是因为预处理语句虽然可以很方便的进行值得替代,但它有个比较致命的缺点,即预处理语句仅仅只是简单值替代,缺乏类型的检测机制。这样预处理语句就不能享受C编译器严格类型检查的好处,正是由于这样,使得它的使用存在着一系列的隐患和局限性。

from geeksforgeeks

1) Normal Pointer
#include <stdio.h>
int main(void)
{
    int i = 10;
    int j = 20;
    int *ptr = &i;        /* pointer to integer */
    printf("*ptr: %d\n", *ptr);
  
    /* pointer is pointing to another variable */
    ptr = &j;
    printf("*ptr: %d\n", *ptr);
  
    /* we can change value stored by pointer */
    *ptr = 100;
    printf("*ptr: %d\n", *ptr);
  
    return 0;
}

Output:
    *ptr: 10
    *ptr: 20
    *ptr: 100

2) Pointer to constant
const int *ptr;
or int const *ptr;

#include <stdio.h>
int main(void)
{
    int i = 10;  
    int j = 20;
    const int *ptr = &i;    /* ptr is pointer to constant */
  
    printf("ptr: %d\n", *ptr);
    *ptr = 100;        /* error: object pointed cannot be modified
                     using the pointer ptr */
  
    ptr = &j;          /* valid */
    printf("ptr: %d\n", *ptr);
  
    return 0;
}


Output:
 error: assignment of read-only location ‘*ptr’

#include <stdio.h>
int main(void)
    int const i = 10;    /* i is stored in read only area*/
    int j = 20;
    int const *ptr = &i;        /* pointer to integer constant. Here i
                                 is of type "const int", and &i is of
                                 type "const int *".  And p is of type                           
                                "const int", types are matching no issue */
    printf("ptr: %d\n", *ptr);
    *ptr = 100;        /* error */
    ptr = &j;          /* valid. We call it as up qualification. In
                         C/C++, the type of "int *" is allowed to up
                         qualify to the type "const int *". The type of
                         &j is "int *" and is implicitly up qualified by
                         the compiler to "cons tint *" */
    printf("ptr: %d\n", *ptr);
    return 0;
}

Output:
 error: assignment of read-only location ‘*ptr’


#include <stdio.h>
int main(void)
{
    int i = 10;
    int const j = 20;
    /* ptr is pointing an integer object */
    int *ptr = &i;
    printf("*ptr: %d\n", *ptr);
    /* The below assignment is invalid in C++, results in error
       In C, the compiler *may* throw a warning, but casting is
       implicitly allowed */
    ptr = &j;
    /* In C++, it is called 'down qualification'. The type of expression
       &j is "const int *" and the type of ptr is "int *". The
       assignment "ptr = &j" causes to implicitly remove const-ness
       from the expression &j. C++ being more type restrictive, will not
       allow implicit down qualification. However, C++ allows implicit
       up qualification. The reason being, const qualified identifiers
       are bound to be placed in read-only memory (but not always). If
       C++ allows above kind of assignment (ptr = &j), we can use 'ptr'
       to modify value of j which is in read-only memory. The
       consequences are implementation dependent, the program may fail
       at runtime. So strict type checking helps clean code. */
    printf("*ptr: %d\n", *ptr);
    return 0;
}

3) Constant pointer to variable.
#include <stdio.h>
  
int main(void)
{
   int i = 10;
   int j = 20;
   int *const ptr = &i;    /* constant pointer to integer */
  
   printf("ptr: %d\n", *ptr);
  
   *ptr = 100;    /* valid */
   printf("ptr: %d\n", *ptr);
  
   ptr = &j;        /* error */
   return 0;
}


Output:
 error: assignment of read-only variable ‘ptr’


A. const char *pContent;
B. char * const pContent;
C. char const *pContent;
D. const char* const pContent;

对于前三种写法,我们可以换个方式,给其加上括号
A. const (char) *pContent;
B. (char*) const pContent;
C. (char) const *pContent;
这样就一目了然。根据对于const修饰非指针变量的规则,很明显,A=C.

对于A,C, const修饰的类型为char的变量*pContent为常量,因此,pContent的内容为常量不可变.
对于B, 其实还有一种写法: const (char*) pContent;
含义为:const修饰的类型为char*的变量pContent为常量,因此,pContent指针本身为常量不可变.
对于D, 其实是AB的混合体,表示指针本身和指针内容两者皆为常量不可变

总结:
(1)  指针本身是常量不可变
(char*) const pContent;
const (char*) pContent;

(2)  指针所指向的内容是常量不可变
const (char) *pContent;
(char) const *pContent;

(3)  两者都不可变
const char* const pContent;



  • const限定符和static的区别

      1. const定义的常量在超出其作用域之后其空间会被释放,而static定义的静态常量在函数执行后不会释放其存储空间。
      2. static表示的是静态的。类的静态成员函数、静态成员变量是和类相关的,而不是和类的具体对象相关的。即使没有具体对象,也能调用类的静态成员函数和成员变量。一般类的静态函数几乎就是一个全局函数,只不过它的作用域限于包含它的文件中。
      3. 在C++中,static静态成员变量不能在类的内部初始化。在类的内部只是声明,定义必须在类定义体的外部,通常在类的实现文件中初始化,如:double Account::Rate=2.25; static关键字只能用于类定义体内部的声明中,定义时不能标示为static
      4. 在C++中,const成员变量也不能在类定义处初始化,只能通过构造函数初始化列表进行,并且必须有构造函数。
      5. const数据成员,只在某个对象生存期内是常量,而对于整个类而言却是可变的。因为类可以创建多个对象,不同的对象其const数据成员的值可以不同。所以不能在类的声明中初始化const数据成员,因为类的对象没被创建时,编译器不知道const数据成员的值是什么。
      6. const数据成员的初始化只能在类的构造函数的初始化列表中进行。要想建立在整个类中都恒定的常量,应该用类中的枚举常量来实现,或者static const。
      7. const成员函数主要目的是防止成员函数修改对象的内容。即const成员函数不能修改成员变量的值,但可以访问成员变量。当方法成员函数时,该函数只能是const成员函数。
      8. static成员函数主要目的是作为类作用域的全局函数。不能访问类的非静态数据成员。类的静态成员函数没有this指针,这导致:1、不能直接存取类的非静态成员变量,调用非静态成员函数2、不能被声明为virtual 
      其中关于static、const、static cosnt、const static成员的初始化问题:
      • 类里的const成员初始化
           在一个类里建立一个const时,不能给他初值
      • 类里的static成员初始化:
            类中的static变量是属于类的,不属于某个对象,它在整个程序的运行过程中只有一个副本,因此不能在定义对象时 对变量进行初始化,就是不能用构造函数进行初始化,其正确的初始化方法是:
      数据类型 类名::静态数据成员名=值



      No comments:

      Post a Comment