const
const

const关键字修饰变量
const int number1 = 10;//const关键字修饰的变量称为常量
int const number2 = 20;
const int val;//error 常量必须要进行初始化
number1 = 30;//error 常量不能被赋值(初始化后不可修改)
除了这种方式可以创建常量外,还可以使用宏定义的方式创建常量
#define NUMBER 1024
常考题:const常量与宏定义的区别是什么?
- 编译器处理方式不同。宏定义是在展开,做字符串的替换;而const常量是在。
- 类型和安全检查不同。宏定义没有类型,不做任何类型检查(有bug运行时才会报错);const常量有具体的类型,在编译期会执行类型检查(有bug编译时报错)。
在使用中,应尽量以const替换宏定义,可以减小犯错误的概率。
const和普通变量的区别
- const修饰的变量不能再作为左值,初始化后值不能被修改
- 编译方式不一样
c和c++中const修饰变量有什么不同
- C中
const
修饰的量可以不初始化,但后面也不能赋值了,不叫常量,而是叫,因此不能用作数组下标:
int main(void)
{
const int a = 20;
int array[a] = {}; // error
return 0;
}
int main(void)
{
const int a = 20;
int *p = (int*)&a;
*p = 30;
// 30 30 30
printf("%d %d %d \n", a, *p, *(&a));
return 0;
}
c++中const特性
const修饰的变量必须初始化,可以用作数组下标
int main(void)
{
const int a = 20;
int array[a] = {}; // pass
int *p = (int*)&a;
*p = 30; //*p此时确实把&a的值改成了30,但是a在编译时都直接替换成20
// 20 30 20
printf("%d %d %d \n", a, *p, *(&a));
//printf("%d %d %d \n", 20, *p, 20);
return 0;
}
- C++是将a在**都直接替换**成20,这就是为什么必须初始化,不初始化怎么发生替换
c++中的const初始化值为**叫,如果用给const初始化的叫**,因为只有运行时才知道变量的值是多少
int main(void)
{
int b = 20;
const int a = b;
//int array[a] = {}; //常变量不能定义数组
int *p = (int*)&a;
*p = 30;
// 30 30 30
printf("%d %d %d \n", a, *p, *(&a)); //和c语言一样
return 0;
}
答:
- const的编译方式不同,c中,const就是当作一个变量编译生成指令的;在C++中,const常量则会被视为一个编译时的常数,并在。
- c++中const修饰的变量必须初始化;c语言的const可以不初始化叫常变量
- c++中const初始化值为立即数叫常量,可以当数组下标;如果用变量给const初始化的叫常变量,常变量不能当数组下标;
- (运行时赋值)
const修饰的量常见错误
- 常量不能再作为左值(直接修改常量值)
- 不能把常量地址泄漏给一个普通指针或者普通引用变量(间接修改常量值)
int main()
{
const int a = 10;
int *p = &a; // error: invalid conversion from ‘const int*’ to ‘int*’
//杜绝*p = 30出现
const int *p = &a; // ok, 保证*p = x;被禁止
}
const关键字修饰指针
对于指针需要关注两点:
- 指针指向的变量是什么
- 指针本身是什么
int value = 2;
int value1 = 10;
int *p1 = &value1;
p1 = &value;
*p1 = 20000;
常量指针和指针常量
常量指针 (const *):不能修改指针所指内容的值,可以改变指针的指向
指针常量 ( * const):可以修改指针所指内容的值, 不可以改变指针的指向
int number1 = 10;
int number2 = 20;
const int * p1 = &number1;//常量指针,Pointer to const
*p1 = 100;//error 通过p1指针无法修改其所指内容的值
p1 = &numbers;//ok 可以改变p1指针的指向
int const * p2 = &number1; //常量指针的第二种写法
int * const p3 = &number1;//指针常量,const pointer
*p3 = 100;//ok 通过p3指针可以修改其所指内容的值
p3 = &number2;//error 不可以改变p1指针的指向
const int * const p4 = &number1;//两者皆不能进行修改
顶层const和底层const
顶层const:指的是const修饰的变量本身是⼀个常量,⽆法修改,指的是,就是 底层const:指的是const修饰的变量所指向的对象是⼀个常量,指的是,就是
int a = 10;int* const b1 = &a; //顶层const,b1本身是⼀个常量
const int* b2 = &a; //底层const,b2本身可变,所指的对象是常量
const int b3 = 20; //顶层const,b3是常量不可变
const int* const b4 = &a; //前⼀个const为底层,后⼀个为顶层,b4不可变
const int& b5 = a; //⽤于声明引⽤变量,都是底层const
注意:
const int b3 = 20;
b3是所修饰的变量,所以是****- ⽤于声明引⽤变量,都是底层const
区分作⽤:
- 执⾏对象拷⻉时有限制,常量的底层const不能赋值给⾮常量的底层const
- 使⽤命名的强制类型转换函数const_cast时,只能改变运算对象的底层const(即)
const与二级(多级)指针结合

实际上没有多级指针,只有一级指针,
const int **q
=>const int * *q
,p
和*q
都指向0x100
,==const int **q
表示*q
(0x100
)存放的数据类型应该是常量指针类型const int *
==🍗🍗🍗
const int **q; // const修饰**q, **q不能被赋值,*q和q可以被赋值
int *const *q; // const修饰*q, *q不能被赋值,**q和 q可被赋值
int **const q; // const修饰q, 只有q不能被赋值
//错误的例子
int main()
{
int a = 10;
int *p = &a;
const int **q = &p; // error, const int ** <= int**
// 假如有const int b; *q = &b; 由于*q和p相同,相当于通过p可以间接修改b的值
}
在C++中,
int*
可以隐式转换为const int*
,因为这样做增加了对数据的保护,不会改变原有数据的非const性质。但是,int**
(指向int
指针的指针)和const int**
(指向const int
指针的指针)之间并不是这种简单的类型兼容关系。当您尝试将
int** p
赋值给const int** q
时,您实际上是在尝试将一个指向非const指针的指针赋值给一个指向const指针的指针。这两种类型并不兼容,因为q
期望的是一个指向const int
指针的指针,而p
是一个指向可能修改其指向的int
值的指针的指针。换句话说,即使
*p
(即p
所指向的内容)可以被转换为const int*
,p
本身(即指向int*
的指针)也不能被转换为const int**
可修改为如下方可通过编译🍗
int main() // 法一
{
int a = 10;
const int *p = &a; //p存放的是const int *类型的数据
const int **q = &p; // ok,*q是的类型是const int *
}
int main() // 法二
{
int a = 10;
int *p = &a;
const int *const*q = &p; // ok,此时*q是常量,*q类型是const int *没有问题
}
const和指针的类型转换()🍗🍗🍗
int* <= const int* // error,因为解引用会修改const的值
const int* <= int* //OK
int ** <= const int ** //error
const int** <= int** // error
int** <= int *const* //error,const与一级指针结合,可转换成 * <= const *判断,即第一种
int *const* <= int** //ok,同第二种情况
习题
#include <typeinfo>
int *q1 = nullptr;
int *const q2 = nullptr;//const修饰的是q2,因此q2不能
cout << typeid(q1).name() << endl; //int* //Pi
cout << typeid(q2).name() << endl; //int* //Pi
int a = 10;
int *p1 = &a;
const int *p2 = &a; //const int * <= int *,OK
int *const p3 = &a; //int * <= int *,OK
int *p4 = p3; //int * <= int *,OK
int a = 10;
const int *p = &a;
int *q = p; //int * <= const int * ,error
注意辨析:p存放的是a的地址,p又赋值给q,a是变量值可以修改,那q可不可以修改❌
q 和有没有a没有关系,不管是变量地址给p还是常量地址给p,对于编译器来说p存放的就是整型常量的地址
const int *
// 例一:
int a = 10;
const int *p = &a; // int* <= int*
int *q = p; // int* <= const int*,error
//例二:
int a = 10;
int *const p = &a; // int* <= int*
int *q = p; // int* <= int* ,ok
//例三:
int a = 10;
int *const p = &a; // int* <= int*
const int *q = p; // const int* <= int*,OK
//例四:
int a = 10;
int *p = &a;
const int **q = &p; // const int ** <= int **,error, *q<=>p
//例五:
int a = 10;
int *p = &a;
int **const q = &p; // int** <= int**,OK
//例六:🍔🍔🍔
int a = 10;
const int *p = &a;
int *const* q = &p;
//int *const* <= const int**,两个const分开看
//等号左边const修饰*q,const* <= *, OK
//因为qcun'cint *类型,int* <= const int * ,error
函数指针:指向函数的指针
指针函数:返回类型是指针的函数
数值指针:指向数组的指针
指针数组:存储类型为指针的数组
//函数指针 指针函数
//int (*pf)(int) int* pf(int)
//
//数组指针 指针数组
//int (*pArray)[] int* pArray[]
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
//void *(*start_routine) (void *) 就是函数指针
在 C 语言中,可以通过
在传统的 C 语言中,没有直接的语言支持来实现面向对象编程中的多态性(polymorphism)。多态性是面向对象编程的一个重要特性,可以通过继承和虚函数来实现。然而,我们可以使用一些技巧来模拟多态性的概念。具体而言,可以通过定义一个包含函数指针的结构体,并使用不同的函数实现来实现多态性的效果。
#include <stdio.h>
typedef struct {
void (*speak)(void);
} Animal;
typedef struct {
Animal base;
const char* name;
} Dog;
typedef struct {
Animal base;
const char* name;
} Cat;
void dogSpeak(void) {
printf("The dog barks.\n");
}
void catSpeak(void) {
printf("The cat meows.\n");
}
int main() {
Dog dog;
dog.base.speak = dogSpeak;
dog.name = "Tom";
Cat cat;
cat.base.speak = catSpeak;
cat.name = "Jerry";
Animal* animals[] = { (Animal*)&dog, (Animal*)&cat };
int i;
for (i = 0; i < 2; i++) {
printf("%s: ", i == 0 ? dog.name : cat.name);
animals[i]->speak();
}
return 0;
}
const关键字修饰成员函数
const关键字修饰对象
[对象的组织 | 张威的编程学习笔记 (gitee.io)](https://iszhwei.gitee.io/ccpp/03 类和对象/组织对象.html)
课堂代码
#include <iostream>
using std::cout;
using std::endl;
//宏定义发生的时机是在预处理阶段,字符串替换,有bug会到运行时才会发现
#define MAX 10
#define multiply(x, y) ((x) * (y))
void test()
{
//发生时机在编译阶段,会进行类型安全检查,如果有bug在编译时候就会出现
//内置类型:char/short/int/long/double/float/void *
const int number = 10;//const修饰的变量称为常量,必须在定义的时候进行初始化
/* number = 20;//赋值,常量不能进行赋值 */
int const number2 = 20;
}
//函数指针 指针函数
//int (*pf)(int) int* pf(int)
//
//数组指针 指针数组
//int (*pArray)[] int* pArray[]
void test2()
{
int value = 2;
int value1 = 10;
int *p1 = &value1;
p1 = &value;
*p1 = 20000;
cout << endl;
int value2 = 200;
const int *p2 = &value2;//当const位于*左边的时候,常量指针(pointer to const)
/* *p2 = 222;//error,不能修改指针所指变量的值 */
p2 = &value;//ok,可以改变指针本身(指向)
cout << endl;
int value3 = 300;
int const *p3 = &value3;//当const位于*左边的时候,常量指针(pointer to const)
/* *p3 = 333;//error,不能修改指针所指变量的值 */
p3 = &value;//ok,可以改变指针本身(指向)
cout << endl;
int value4 = 400;
int * const p4 = &value4;//当const位于*右边的时候,指针常量(const pointer)
*p4 = 444;//ok,可以修改指针所指变量的值
/* p4 = &value;//error,不可以改变指针本身(指向) */
cout << endl;
int value5 = 500;
const int * const p5 = &value5;//双const
/* *p5 = 555;//error,不可以修改指针所指变量的值 */
/* p5 = &value;//error,不可以改变指针本身(指向) */
}
int main(int argc, char **argv)
{
test2();
return 0;
}