第八章 常量 Thinking in C++ V1

值替代:

在C中可以使用宏定义,例如:#define pi 3.1415  

在C++中使用const替代 常量的宏定义,这样可以增加程序的安全系数。 

 

C++中cosnt默认为内部连接 ,而在C中cosnt默认为外部连接。

 

书中说编译器无法获得内存中的数据,这只是对某些编译器成立,在VS2013中下面的代码1无法通过编译:

//代码1
int array1[] = {1, 2, 3, 4}; int array2[array1[1]]; cout<<sizeof(array2);

在VS2013中无法通过编译,

提示:error C2133: 'array2' : unknown size

//代码2   
int B = 9; char C[B];

在VS2013中无法通过编译,

提示:error C2133: 'C' : unknown size

//代码3   
 const int B = 9;
 char C[B];

VS2013可以通过编译                      

 说明编译器对B做了优化(常量折叠)。

说明VS2013的编译器无法在编译时获得array1[1]中的数据。但在g++编译器中代码1可以通过编译并且输出为8 。

 

C中和C++中对const变量的定义有本质的差别:

C    :   一个不可以被改变的变量,这个变量无法直接更改,但可以使用间接的方法,C中常量一定会被分配内存空间(不在只读存储空间)。在  C  中const默认为外部连接。在C中可以声明:const int bufsize ;不初始化,但C++不行。

C++:   一个常量,编译期间的常量。(const在C++中还有其他的意义,见下面)声明和定义一般同时完成(除了类中的常量),因为定义后无法更改。 在C++中const默认为内部连接。故需要加上关键字extern才能使其被外部文件连接。 

C++中使用类似C中使用指针的方法改变const变量的行为没有定义(未定义行为),也就是更改结果与编译器实现有关。例如:

同样的代码不一样的执行结果: 


//
代码1: C++ #include<iostream> using namespace std; #define PR(x) (cout<<#x##" = " <<x<<endl); int main() { volatile const int M = 9; PR(M) int *pInt =(int *) &M;   *pInt = 6; PR(M) PR(*pInt) system("pause"); }

 C++编译输出:

M = 9

M = 6

*pInt = 6

//代码2: C++
#include<iostream>

using namespace std;

#define PR(x) (cout<<#x##" = " <<x<<endl);  
int main()
{
    const  int M = 9;
  //不一定开辟空间        
    PR(M)
 //强迫编译器为常量开辟空间
int *pInt =(int *) &M;
 
        *pInt = 6;
    PR(M)
    PR(*pInt)
    
    system("pause");

}

C++编译输出:

M = 9

M = 9

*pInt = 6

//代码3: C
#include<stdio.h> using namespace std;
#define PR(x) {printf(#x);printf("=") ;
printf("%d\n" , x);} int main() { const int M = 9;
  //C编译器一定会为常量开辟空间 PR(M) int *pInt =(int *) &M;
*pInt = 6; PR(M) PR(*pInt) system("pause"); }

C编译输出:

M = 9

M = 6

*pInt = 6

C++中的常量是编译期间的一个定值,故编译器没必要为这个常量分配内存。而且常量的值会保存在符号表中,编译器会将局部const变量进行常量折叠。故如果强迫编译器为常量分配内存,即使在C++中改变了常量在内存中的值,我们在代码中使用的常量的值依旧不会改变,故会出现上面代码2的情况。但是如果在常量的前面添加关键字volatile,告诉编译器不要对const常量进行优化即不做常量折叠,每次使用const常量时都从内存中读取,那么就会出现代码1中的结果。C中一定会为常量分配内存,而且每次使用时都会从内存中读取,故会出现上面的代码3的结果。从上面的结果可知,const常量没有像字符串常量那样被分配在静态存储区。

                           参考资料:http://blog.csdn.net/heyabo/article/details/8745942

下面的 代码可以通过编译但会出现运行时错误:

#include<stdio.h>
#include<stdlib.h>
int main()
{
  char *pch = "Hello Qt !";//字符串会被写入只读存储区,静态存储区,这个只读是由硬件控制的
  const int i = 2;               //奇怪的是,C中const常量不会被写入只读存储器,因为可以使用指针改变其中的值
  int *ip = &i;
  *ip = 3 ;                         //运行时没错
  pch[2] = 'e';                  //运行时会出错,不能对只读存储器进行写操作。

const常量没有像字符串常量那样被分配在只读存储区。

 

const  int *pInt;    

int  const *pInt;      //这两个声明的意思是相同的,pInt指向一个int型常量(这个变量中的值不能变)。

int * const pInt;       //pInt是一个常量型指针(指针内容不可变),其指向一个int型变量。

 

 字符串是默认的常量并且保存在只读存储区,字符串中的数据是无法更改的(一般更改字符串的代码可以通过编译,但在执行时会触发硬件中断)。字符数组一般是变量,字符数组一般在栈中或静态存储区保存,因为是变量所有其中的内容是可以更改的。char *pChar = "Hellow !"这样的代码在技术上而言是错误的,因为赋值号的右侧是字符串而左侧却是一个指针。但编译器允许这样,编译器默认将字符串的首地址赋予指针。

 

重定义的错误是在什么时候发现的?预处理还是链接?还是在预处理和链接时都会发现。

 

在pass-by-value形式的函数前添加关键字const是没意义的,因为完全没有必要,原来的数据一定不会被更改。

 

如果一个函数返回一个const型的对象,那么这个函数不能作为左值,因为其返回的内存空间是不能被更改的,更不可能被赋值。当一个函数返回的是一个对象而且这个对象不是const型时,这个函数可以作为左值,例如:f(x1) = f(x2),在C中是看不见这样的赋值形式的,在C中左值永远都是变量,而不可能是函数的形式。如果一个函数返回的是内建类型,那么编译器不允许其作为左值。允许返回值为对象的函数作为左值可以写出链式的表达式例如:f(x).fun(y) ,其中fun( y )为f(x)返回值的一个成员函数。可以将上面的代码作为右值,这样可以简化代码。 

 

类中的常量:

类中的常量有两种形式:

1、对象中的常量:对于每一个对象而言某一个变量是常量,由同一个类创建对象的常量值不同,一般这样的常量在类中声明的形式为const int data;  必须在构造函数初始化列表中以类似FUN(...) : data(9)...{ function }的形式初始化这些数据(必须以函数的形式初始化,不能用等号的形式)。

2、类常量:对于由同一个类创建的对象而言,每一个对象中这个常量都是相同的,这样的常量的声明形式如:static cosnt data = T;这样的常量在声明的同时必须初始化也可以使用无标记枚举来实现这样的效果。

  这类常量只是在编译期间存在,因为编译器没必要为这样变量分配内存。

 

const对象和成员函数:

  const对象只能调用对应类中的const成员函数。其中cosnt成员函数的定义,必须声明和定义的时候在参数表之后函数体之前添加const关键字。如果一个成员函数被定义为const类型那么在函数体内将无法更改对象中任何数据成员(除非这个数据被被关键词mutable修饰),否则将无法通过编译。

  

//const成员函数的声明和定义
class test
{
public:
   test(int a);
   void Nchange(int b ) const; //const成员函数的声明
private:
    const int m_a;
    int m_c;
};

void test::Nchange(int b )const         //const成员函数的定义
{
        //m_c = b;//无法通过编译
    int c = b;//c 不是类中的成员数据,故可以通过编译
}
const成员函数的声明和定义形式

  

posted @ 2015-01-20 21:00  jiahu  阅读(154)  评论(0)    收藏  举报