C++梁哥笔记day2
一、语法的增强
- 以下代码在C语言中好使,在C++中会报错
1
2
3
4
5
6
7
int main(){
int a = 10;//有赋值--->定义
int a;//同名且没有赋值--->声明
printf("a=%d\n",a);
return 0;
}
- C语言中,虽然有警告但还是可以编译运行,在C++中则不行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15//i没有写类型可以传任意类型
int fun1(i){
printf("%d\n",i);
return 0;
}
//i没有写类型可以传任意类型
int fun2(i){
printf("%s\n",i);
return 0;
}
//没有写参数,代表可以传任何类型的实参
int fun3(){
printf("fun3\n");
return 0;
} - 更严格的类型转换
在C++中不同类型变量一般是不能直接赋值的,需要进行相应的强制类型转换。C语言中编译器可以编译通过。1
2
3
4
5
6enum COLOR{GREEN, RED, YELLOW};
int main(){
COLOR mycolor = GREEN;
mycolor = 10;//C++中编译出错
return 0;
}
二、对结构体的增强
C语言中定义结构体变量需要加上struct关键字,C++中不需要。
1
2
3
4
5
6
7
8
9
10
11struct stu{
int num;
char name[32];
};
int main(){
//C语言中必须加struct,不然会报错
struct stu bob= {100,"bob"};
//C++语言中,可不加struct
stu lucy = {200,"lucy"};
return 0;
}C语言中的结构体只能定义成员变量,不能定义成员函数。C++既可以定义成员变量,也可以定义成员函数。
1 | struct stu{ |
运行结果:
三、bool类型
标准C++的bool
类型有两种内建的常量true
(转换为整数1)和false
(转换为整数0)表示状态。
这三个名字都是关键字。bool
类型占1字节大小,给bool
类型赋值时,非0值会自动转换为true
(1),0会自动转换为false
(0)
案例1:
1 | void test1(){ |
运行结果:
C语言中也有bool类型,在C99标准之前是没有bool关键字的,C99增加了bool类型,包含头文件,stdbool.h就可以使用C++一样的bool类型。
四、三目运算符的增强
- C语言中三目运算符表达式返回值为数据值,为右值,不能赋值。
案例2:1
2
3
4
5void test2(){
int a=10,b=20;
printf("%d\n",a>b?a:b);
//a>b?a:b=100;//错误 不能作为左值 相当于20=100
} - C++中三目运算符表达式返回值为变量本身(引用),为左值,可以赋值。
案例3:运行结果:1
2
3
4
5
6
7
8void test3(){
int a=10,b=20,c=0;
c=a>b?a:b;
//cout<<a>b?a:b;<<endl;这样写会报错
cout<<c<<endl;
a>b?a:b=100;//正确 整体返回的是变量b 相当于b=100
cout<<"b="<<b<<endl;
}
五、const详解
1、const概述
const
单词字面意思是常数、不变的。它是c/c++中的一个关键字,是一个限定符,它用来限定一个变量不允许改变,它将一个对象转换成一个常量
2、C语言中的const
常量的引进是在c++早期版本中,当时标准c规范正在制定。那时,尽管c委员会决定在c中引入const,但是,他们c中的const理解为“一个不能改变的普通变量”,也就是认为const修饰的应该是一个只读变量,既然是变量那么就会给const分配内存,并且c中const是一个全局只读变量,c语言中const修饰的只读变量是外部连接的,也就是说其他文件也可以使用。const int arrSize = 10;
int arr[arrSize];
看似是一件很合理的代码,但是是错误的,因为arrSize占用某块内存,所以c编译器不知道它在编译时的值是多少。
- 在C语言中案例4:
1
2
3
4
5
6
7
8
9const int a = 10; //不要把a看成一个常量
//a的本质是变量,只是它是一个只读的变量
/* !!!!!!重要!!!!!!!
*只是不能通过变量名直接改变空间的内容
*但是可以通过其地址来修改其空间内容
*前提是要地址对应的空间区域可读可写
*例如,定义在全局的const 变量在文字常量区
*其空间区域都不可修改,即使知道其地址也不能修改
*/运行结果:1
2
3
4
5
6
7void test4(){
const int num=10;
int *p=(int *)#
printf("num=%d\n",num);
*p=200;
printf("num=%d\n",num);
}
总结:
- const修饰全局变量data,变量名只读,对应的内存空间在文字常量区(只读),不能通过data的地址,修改空间内容。
- const修饰局部变量num,变量名只读,对应的内存空间在栈区(可读可写),可以通过data地址,间接地修改空间内容。
- const修饰的变量是外部连接,其他文件也可以使用。
3、C++中的const深入理解
(1) 在C++中,出现在所有函数之外的const作用于整个文件(也就是说对其他文件不可见),默认为内部连接。
如果要在其他文件使用只读的全局变量 必须在定义的时候加extern将变量转换成外部连接
(2) 在C++中,一个const不必创建内存空间,而在c中,一个const总是需要一块内存空间。在c++中,是否为const常量分配内存空间依赖于如何使用。一般说来,如果一个const仅仅用来把一个名字用一个值代替(就像使用#define一样),那么该储存区空间不必创建。如果储存空间没有分配内存的话,在进行完数据类型检查后,为了代码更加有效,值也许会折叠到代码中。不过,取一个const地址,或者把它定义为extern,则会为该const创建空间。
案例5:
1 | void test5(){ |
运行结果:
想想明明就改成2000了,*p=2000,为什么num尽然还是10呢?
1、对于基础数据类型,也就是const int a = 10;这种,编译器会把它放到符号表中,不分配内存,当对其取地址时才会分配内存。
这样的话,上面的案例5的现象就很好解释了,当我们对其取地址时,系统给它分配了空间,这个空间的原始内容是10,然后我们将其改为2000,但是符号表中,num对应的值还是10,所以当我们输出num的值时,num的值是从符号表里面取的,所以输出的num仍然是10,但是系统为num分配的空间*p的值是2000。
运行结果:
2、对于基础数据类型,如果用一个变量初始化const变量,例如const int a = b;那么也是会给a分配内存,而且是直接开辟空间,不会把a放到符号表中。
案例6:
1 | void test6(){ |
运行结果:
3、对于自定数据类型,比如类对象,那么也会分配空间,且不会放到符号表中
案例7:
1 | struct person{ |
运行结果:
六、尽量以 const 替换#define
在旧版本 C 中,如果想建立一个常量,必须使用预处理器”#define MAX 1024;我们定义的宏: MAX 从未被编译器看到过,因为在预处理阶段,所有的 MAX 已经被替换为了 1024,于是 MAX 并没有将其加入到符号表中。当我们使用这个常量获得一个编译错误信息时,可能会带来一些困惑,因为这个信息可能会提到 1024,但是并没有提到 MAX.如果 MAX 被定义在一个不是你写的头文件中,你可能并不知道 1024 代表什么,也许解决这个问题要花费很长时间。解决办法就是用一个常量替换上面的宏。
const int max= 1024;
const 和 #define 区别总结:
- const 有类型,可进行编译器类型安全检查。#define 无类型,不可进行类型检查.
- const 有作用域,而#define 不重视作用域,默认定义处到文件结尾,如果定义在指定作用域下有效的常量,那么#define 就不能用。
案例8:宏没有类型,const有
- 宏常量没有类型,所以调用了 int 类型重载的函数。const 有类型,所以调用希望的 short 类型函数?运行结果:
1
2
3
4
5
6
7
8
9
10
11
12
const short param = 128;
void func(short a){
cout << "short!"<< endl;
}
void func(int a){
cout <<"int"<< endl;
}
void test8(){
func(PARAM);
func(param);
}
案例9:宏作用域是当前整个文件,const作用域以定义情况决定
2. 宏不重视作用域
1 | void my_func(){ |
运行结果:
问题:宏常量可以有命名空间吗?
没有。
案例10:
3. 宏不能作为命名空间内的成员
1 | namespace MySpace{ |
总结:
- 在C++中,const定义的变量默认是内部连接,要把它变成外部连接要在定义的时候加extern,在其他文件使用的时候声明就行了。
- const int data = 10;//data先放入符号表
如果对data取地址,系统才会给data开辟空间 - const int a = b;//b是变量名 系统直接给a开辟空间,而不放入符号表
- const修饰自定义数据时,系统为自定义数据开辟空间,不放入符号表。
- 尽量以 const 替换#define