C++入门
命名空间
将全局空间进行划分,全局空间也被称为默认命名空间,命名空间可以相互嵌套。
例如:
这里在全局空间中,开辟了三个大的命名空间分别为Name1,Name2, Name3,其中Name3中又有两个命名空间Name4和Name5;
//命名空间的定义,命名空间内可以写变量、函数、宏定义
namespace Name1
{
int a;
}
namespace Name2
{
int a;
int b;
int c;
}
命名空间的使用:
1.使用域解析符
Name1::a = 10;
Name2::a = 20;
cout<<"a1 = "<<Name1::a<<", a2 = "<<Name2::a<<endl;
2.使用using关键字
//将命名空间Name1打开,后面直接可以使用命名空间Name1中的变量,函数,宏定义
using namespace Name1;
a = 10;
Name2::a = 20;
cout<<"a = "<<a<<endl; 结果是:a = 10
原因:
**using后面但凡没有明确指明具体命名空间的变量,函数,宏定义,默认使用的是Name1中的**
当然也可只开启部分内容:
比如,using Name2::c;
后面但凡没有指明具体命名空间的c,默认使用Name2中的C;
3.命名空间之间命名冲突
using namespace Name1;
using namespace Name2;
a = 10; //有歧义,不知道使用哪一个命名空间内的a
Name1::a = 10;//使用域解析符可以解决两个命名空间明明冲突的问题
如果定义了一个全局变量a;
a = 10; //有歧义,全局变量与命名空间发生冲突
::a = 10;//使用默认命名空间的域解析符,使用全局变量
c++标准库和std命名空间
C++ 是在C语言的基础上开发的,早期的 C++ 还不完善,不支持命名空间,没有自己的编译器,而是将 C++ 代码翻译成C代码,再通过C编译器完成编译。这个时候的 C++ 仍然在使用C语言的库,stdio.h、stdlib.h、string.h 等头文件依然有效;此外 C++ 也开发了一些新的库,增加了自己的头文件,例如:
iostream.h:用于控制台输入输出头文件。
fstream.h:用于文件操作的头文件。
complex.h:用于复数计算的头文件。
和C语言一样,C++ 头文件仍然以.h为后缀,它们所包含的类、函数、宏等都是全局范围的。
后来 C++ 引入了命名空间的概念,计划重新编写库,将类、函数、宏等都统一纳入一个命名空间,这个命名空间的名字就是std。std 是 standard 的缩写,意思是“标准命名空间”。
但是这时已经有很多用老式 C++ 开发的程序了,它们的代码中并没有使用命名空间,直接修改原来的库会带来一个很严重的后果:程序员会因为不愿花费大量时间修改老式代码而极力反抗,拒绝使用新标准的 C++ 代码。
头文件:
c语言:去掉.h, 并在前面加c 例如,stdio.h => cstdio
c++: 去掉.h 例如,iostream.h => iostream
原来的c++头文件:
例如:
test.h
{
int a;
}
新文件的名字:test
{
namespace std;
{
int a;
}
}
C++ PK C
1.实用性加强
c语言规定所有变量的定义必须放在开头,c++对变量定义的位置没有要求,建议是在使用的时候再定义。
最小化变量的适用范围,在用的时候再去定义变量
2.register关键字的变化
首先讲一下,CPU、内存、寄存器三者之间的关系,它们之间的关系用下图进行说明:
内存单位:字节
将内存划分为很多小块,每个小块都有编号,编号对应于地址,也就是指针。地址也只在内存当中才有意义。
寄存器脱离内存,因此没有地址这一说法。
在C++中,如果对一寄存器变量取地址操作,那么register声明无效。但在C语言中,如果对一寄存器变量取地址操作,那么编译就不能通过。
举个例子形象的说明,这三者的关系:
内存就像是军机大臣,寄存器就是太监,CPU就是皇上。大臣将要处理的事情交由太监转交给皇上来处理,皇上处理后再交给太监转交给大臣。
3.全局变量重复定义
C语言中允许全局变量重复定义;
C++中不允许全局变量重复定义;
4.struct类型加强
C语言中,struct只是一种数据的集合,而不是一种新的数据类型,所以在定义时要在变量前加上struct关键字。
例如:
struct Student
{
int age;
char name[20];
};
int main()
{
struct Student stu = {10, "小明"};
return 0;
}
但在C++中,认为结构体是一种新的数据类型,可以直接用来定义变量;
例如:
struct Student
{
int age;
char name[20];
};
int main()
{
Student stu = {20, "小红"};
return 0;
}
除此以外,还有三点也要注意:
- C语言中,函数没有参数时,调用可以填写任意个数的实参;
- C语言中,函数可以没有返回值;
- C语言中,形参可以没有类型。
对于C++,上面三种情况都不允许发生。
5.新增bool类型
bool值只有2种,一个为真,值为1,另一个为假,值为0;
C++中,0表示假,所有非0都为真。
#include <iostream>
using namespace std;
int main()
{
bool b = true;
bool b1 = false;
cout << "b = " << b << ", b1 = " << b1 << endl; // b = 1, b1 = 0
int a = 2;
b = a;
cout << "b = " << b << endl; // b = 1;
b++;
cout << "b = " << b << endl; // b = 1;
b = b - 1;
cout << "b = " << b << endl; // b = 0;
b = -1;
cout << "b = " << b << endl; // b = 1;
return 0;
}
6.浮点型数与0进行比较
float精度为7位,double 精度为15位。
float f = 1.2f;
if(f - 0.0000001 < 0 && f + 0.0000001 > 0) //**0.0000001**这个精度取决于客户要求
{
cout<<f<< " > 0"<<endl;
}
7.三目运算符的增强
C++中的三目运算符可以当左值,而C语言返回的是数据的值,C++返回的是变量本身。
#include <iostream>
using namespace std;
int main()
{
int a = 10;
int b = 20;
int c = (a > b) ? a : b;
(a > b ? a : b) = 90; // 在C语言中,*(a > b ? &a : &b) = 90,也可以将b的值变为90
cout<<"a = "<<a<<", b = "<<b<<", c = "<<c<<endl; // a = 10, b = 90, c = 20
return 0;
}
注意:当三目运算符当左值使用时,表达式中不能有常量。
8.const:设置变量的属性为只读
C语言中,const修饰的是变量,不能通过变量名修改内存中的值,但可以通过其他方式进行修改;
const ina a = 10;
int *p =(int *)&a;
*p = 20;
printf("a = %d\n", a); // a = 20;
C语言通过上面两行代码,就能改变常量的值
在C++中,const修饰的是一个常量,放在符号表中,符号表由编译器维护。
键值 | 值 |
---|---|
a | 10 |
… | … |
如果对const修饰的常量进行取地址操作,则编译器会为这个变量分配一个内存,但这段内存不可使用。
const ina a = 10;
int *p =(int *)&a;
*p = 20;
printf ("&a = %p\n", &a); // 004FFBA8
printf ("p = %p\n", p); // 004FFBA8
printf ("a = %d, *p = %d\n", a, *p); // a = 10, *p = 20;
原因是:&a中的a并不是符号表内的a,而是新的内存中a,因此p与a的地址相同,但当输出时,a是符号表中。
在C++中,建议使用const代替宏常量,因为C++中的const就是常量。
最典型的例子就是,在C语言中数组的容量不能用常量来写,即
const int a = 10;
int b[a]; // 是不正确的
但在C++中,这是允许的。
原因:
- 宏常量不会做类型检查,在预处理器件完全替换,const常量在编译时处理,会做类型检查。
- 宏常量不会做作用域检查,const
C语言中:
void func()
{
#define B 20;
}
int main()
{
printf("B = %d\n", B); //B = 20;
return 0;
}
C++中:
void func()
{
const int a = 25;
}
int main()
{
printf("a = %d\n", a);
return 0;
}
编译不会通过