跳转至

const

不能改变内容的常量,C++用的多。

C和C++

C语言中

头文件里声明:extern const int BUFSIZE; 外部常量声明

源文件里定义:const int BUFSIZE = 100;

引入头文件,替换的时候都是声明。

在C语言中默认是外部链接性

在C语言会出现重复定义 因为C语言const默认外部链接性,其它文件引用包含const的头文件的时候,预处理 相当于把头文件换成了const的定义 所以会有多处的重复定义

C语言使用const必须写一个源文件,默认外部链接性,extern做一个声明(引用)。

C语言里 总是分配内存空间

C++

C++中不会每次都把引用的头文件替换成对应的常量定义,那样多个文件引入头文件,就会有多处替换,重复,效率低。

define就是文本替换,const是常量折叠,保存在符号表里,在常量表中去查找替换(如同使用#define一样)。

C++中并没有定义一个常量分配内存,而是做了一个常量折叠。

在C++中默认是内部链接性

因为在C++中const默认的链接性是内部链接性。即使头文件被包含,头文件替换对应的定义,但是是内部链接性,所以不会出错。

C++可以直接在.h头文件使用。

C++里通常不会分配内存空间,有时会分配内存空间

  1. 使用外部链接性

在源文件中使用extern const int BUFSIZE = 100;这样C++就会给BUFSIZE分配内存。(这是定义)

在头文件中声明extern const int BUFSIZE;。 (这是声明)

这样的就是外部链接性 分配内存。

  1. 取地址

    const int i = 100;//不分配内存
    const int j = i + 10;
    long address = (long)&j;//这里如果不取地址j不分配内存,一取地址就分配了内存
    char bufs[j + 10];//这里做常量折叠(查找替换)
    
  2. 用于集合(数组,struct,类)

普通的可以放到符号表里,所以不分配内存,而数组值太复杂了,不能放符号表里。

分配内存 只有在运行的时候才有值 在编译的时候值是未知的

  • #define 在预处理的时候做一个文本查找替换,无法检查类型。

  • const 编译器会把BUFSIZE 放到符号表里,没有分配内存。编译的时候都把BUFSIZE换成100。

编译器做的常量折叠,首先会检查类型。通过安全之后才替换。

#include <iostream>

const int bs = 100;
char buf[bs];

上面代码在编译的时候

C语言不知道bs值是多少,在运行的时候才知道是100,并且不能改。所以C语言中编译的时候会出错。

但是在C++中可以,并不给bs分配内存,只做常量折叠(查找替换),把bs放符号表里,编译的时候查找,知道bs是100。

const指针

  • 指向const常量的指针
  • const常量指针
  • 赋值和类型检查
  • 可以把非const对象的地址赋值给一个指向const指针
  • 不能把const对象的地址赋值给一个指向非const指针

指向const的指针

const int* u;

指针u必须指向常量。

u是变量 是指针 指向const int( 常量整型),是指向常整型的指针。

const int e = 2;
u = &e;

u可以指向常量。

因为u是常量 所以不可以通过指针修改

*u = 300这句是错误的。

u是指针 u指向的是常量 不能被修改。

可以把非const对象的地址赋值给一个指向const指针

int d = 1;
u = &d;

只能使指针u去读取数据 例:输出*u。

不能通过指针修改,例:*u = 300;。

定义const指针

int* const w = &d;

w是const指针,常指针,指向整型。

w指向&d,就永远指向&d,不允许修改指向。但是这个数是可以被修改的,*w = 2;

常指针 指向常整型

const int e = 100;

const int* const x = &e;

x常指针 指向常整型

int d = 1;
const int* const x2 = &d;

下面这两种写法一样:const都在*左边

const都是修饰int整型,指针指向const整型。

const int*u;
int const*v;

第二种:const在*右边

const用来修饰指针,const指针。

int* const w = &d;

下面的e是const 但是指针n不是const,所以赋值错误。

const int e = 100;
int* n = &e;        //(这种错误)

可以把非const赋值非const,const指针保证不会对它修改。即使它可以修改,也不修改。这是安全的。

e是const,把它赋值给非const。通过指针可以对它修改,不是安全的。所以通不过。但是可以做一个强制转换:

int *k = (int *)&e;

默认不行,但是强制了也可以这样做,只是很危险。尽量不要这样转换。不能修改,只能读取。

*k = 111; //错误的
cout << *k << endl; //可以
  • 不能修改值。

非常指针const int*u

  • 不能修改指针指向。

常指针int* const w

总结

const修饰什么,什么就不可以修改。

int* const w = &d;//w不可以修改
const int* u;//*u不可以修改

字符串

const char* cp = "howdy";

应该有const。

C语言早期是下面这种:

char* cp = "howdy";

这种有问题。

cp不能被修改。

cp[2] = 'a' //错误
*(cp + 2) = 'a' //错误

如果要修改 就要用字符数组

char cp2[] = "howdy";

cp2[2] = 'a';

const修饰函数参数和返回值

const函数参数

传参数 参数也可以是指针(引用也可以)

  1. 传普通参数
  2. 利用指针方式传参数
  3. 利用引用方式传参数

参数传递的过程中 可以加上const,实际根据需要来确定要不要加const。

void f4(const int i)
{
}

void f5(const int* pi)
{
}

void f6(const int& ri)
{
}
  1. 普通传递

按值传递

传递的是拷贝 改的是拷贝复制品。不是原来的数据并没有改变本身 所以是不会变的

如果传递的参数是一个很大的参数class。函数传递参数class。传递的是复制 复制多占用内存 复制需要时间,效率不高。

传比较大的对象,可以传指针,也可以传引用。

地址复制了一份。地址没那么大,速度会快。

  1. 利用传指针的方式

参数可以很大可以很小,都没关系。传的是指针。

可以通过指针对原来的数据进行修改。因为有地址,所以可以对原来的数据进行修改。

  1. 引用和指针完全一样

也会发生修改。

指针和引用都是地址

两种情况用指针和引用

  1. 想对原始数据进行修改。
  2. 参数数据对象很大(clase,数组) 用指针。速度快。

指针引用或者普通传参都可以加const

参数有const和没有const的不同

  • 有const 传进来的参数不允许在内部修改。传递进来的数据不许被修改。加了const 就加了保护。

  • 没有const 传进来的参数可以修改。

const函数返回值

返回C++内置类型(int)自己写的类型(class)

返回指针

返回引用。

int g1()
{
    return 1;
}

int* g2(int* x)
{
    (*x)++;
    return x;
}

int& g3(int& x)
{
    x++;
    return x;
}

这三个函数 前面都可以加const

加const的不可以被修改,不加const的可以被修改。

  • 函数返回值

函数内部的这个返回值是局部的 函数结束之后就没了。返回之后就没了。外面接收的也是一个复制品,和函数普通参数传递一样。按值传递。

  • 返回指针

复制的是地址,得到地址的复制,对原来的数据进行操作修改。

不想修改则加上const。

  • 引用 同理。和地址一样。可以修改,不想修改则可以加上const。

需要对返回的数据进行保护就加上const。

void u(const int* cip)
{
    //*cip = 2;//不可以
    int i = *cip;//可以
    //int* ip2 = cip;//不可以
}

返回值是一个指向const整型的const指针

const int* const w()
{
    static int i;
    return &i;
}
//这两种接收都可以,只要第一个是const就行
const int* const ccip = w();
const int* cip2 = w();
  • 非const可以赋值给一个const。
  • const不能赋值给一个非const。

总结:

这都是一种保护措施。

普通的那种很少传const,本身就是复制品,不怎么需要。

多数传指针 传引用都是用const。指针和引用可以修改数据 不允许的就需要加const。