namespace命名空间
namespace,是指标识符的各种可见范围。C++标准程序库中的所有标识符都被定义于一个名为std的namespace中。
C++中声明头文件时不使用后缀带.h的,为了和C区别开,
当使用< iostream >的时候,该头文件没有定义全局命名空间,必须使用namespace std;这样才能正确使用cout
namespace三种表示方法
1)直接指定标识符
std::cout << std::hex << 3.4 << std::endl;
2)使用using关键字。
using std::cout;
using std::endl;
using std::cin;
3)声明后,使用
using namespace std;
cout << std::hex << 3.4 << endl;
标准C++引入了关键字namespace(命名空间/名字空间/名称空间/名域),可以更好地控制标识符的作用域。
C++命名空间的使用:
使用整个命名空间:using namespace name;
使用命名空间中的变量:using name::variable;
使用默认命名空间中的变量:::variable
默认情况下可以直接使用默 认命名空间中的所有标识符
-
实用性增强 ,随用随定义
//C语⾔言中的变量都必须在作用域开始的位置定义!!
//C++中更强调语⾔言的“实用性”,所有的变量都可以在需要使⽤用时再定义。 -
变量检测增强,不允许重复定义,拒绝二义性
//在C语⾔言中,重复定义多个同名的全局变量是合法的
// 在C++中,不允许定义多个同名的全局变量
//C语⾔言中多个同名的全局变量最终会被链接到全局数据区的同一个地址空间上 -
struct类型增强
//C语⾔言的struct定义了一组变量的集合,C编译器并不认为这是一种新的类型
// C++中的struct是一个新类型的定义声明 -
C++中所有变量和函数都必须有类型
//C++中所有的变量和函数都必须有类型
//C语⾔言中的默认类型在C++中是不合法的
在C语言中
int f( );表示返回值为int,接受任意参数的函数
int f(void);表示返回值为int的无参函数
在C++中
int f( );和int f(void)具有相同的意义,都表示返回值为int的无参函数
C++更加强调类型,任意的程序元素都必须显示指明类型 -
新增bool类型关键字
C++中的bool可取的值只有true和false
理论上bool只占⽤用一个字节
如果多个bool变量定义在一起,可能会各占一个bit,这取决于编译器的实现
true代表真值,编译器内部用1来表示 (非0)
false代表非真值,编译器内部用0来表示 -
三目运算符功能增强
C语言返回变量的值
C++语言是返回变量本身
C语言中的三目运算符返回的是变量值,不能作为左值使用
(a < b ? a : b )= 30; //err
* (a < b ? &a :& b )= 30; //ok
C++中的三目运算符可直接返回变量本身,因此可以出现在程序的任何地方
(a < b ? a : b )= 30; //ok
注意:三目运算符可能返回的值中如果有一个是常量值,则不能作为左值
使用 (a < b ? 1 : b )= 30;
当左值的条件:要有内存空间;C++编译器帮助程序员取了一个地址而已 -
const增强
如果对一个常量取地址,编译器会临时开辟一个空间temp,让这个指针存放这个临时空间的地址
在C语言中,
const int a = 10;
int *p = (int * )&a;
printf(“a==>%d\n”,a);
*p=11;
printf(“a==>%d\n”,a);
最后打印出a==>10,a==>11
在C语言中,这里的a是假常量,相当于是变量,用const修饰为只读,在栈中开辟空间
const和#defiine的相同
C++中的const修饰的,是一个真正的常量,而不是C中变量(只读)。在 const修饰的常量编译期间,就已经确定下来了
真正的常量,在常量区的符号表
const和#defiine的区别
C++中的const常量与宏定义不同
const常量是由编译器处理的,提供类型检查和作用域检查
宏定义由预处理器处理,单纯的文本替换
- 真正的枚举
c 语言中枚举本质就是整型,枚举变量可以用任意整型赋值。
而 c++中枚举变量, 只能用被枚举出来的元素初始化。
引用
变量名,本身是一段内存的引用,即别名(alias). 引用可以看作一个已定义变量的别名
引用的语法:Type& name = var;
例如:int& b = a; //b是a的别名
引用规则
1 引用没有定义,是一种关系型声明。声明它和原有某一变量(实体)的关系。故而类型与原类型保持一致,且不分配内存。与被引用的变量有相同的地址。
2 声明的时候必须初始化,一经声明,不可变更。
3 可对引用,再次引用。多次引用的结果,是某一变量具有多个别名。
4 &符号前有数据类型时,是引用。其它皆为取地址。
普通引用 在声明时必须用其它的变量进行初始化,引用作为 函数参数 声明时不进行初始化。
引用的意义
1)引用作为其它变量的别名而存在,因此在一些场合可以代替指针
2)引用相对于指针来说具有更好的可读性和实用性
可以用引用解决问题,避免用指针来解决
引用本质
如果我们在去 研究 引用的时候,可以将引用当作一个 常指针 去研究
当在使用 引用 编程的时候,就把引用理解成变量的 别名 就可以了
当我们将引用作为函数参数传递的时候,编译器,会替我们将实参,&取地址给引用,
对一个引用操作,赋值的时候,编译器,会替我们隐藏进行 *操作
\
引用作为函数的返回值
1.当函数返回值为引用时,
若返回栈变量: 不能成为其它引用的初始值(不能作为左值使用)
//将一个引用赋给另一个引用作为初始值, 由于是栈的引用,内存非法,因为,在函数调用完,栈空间会自动释放
2.当函数返回值为引用时,
若返回静态变量或全局变量 ,可以成为其他引用的初始值(可作为右值使用,也可作为左值使用)
//将一个引用赋给另一个引用作为初始值,由于是静态区,内存合法
引用作为函数返回值,
如果返回值为引用可以当左值,
如果返回值为普通变量不可以当左值。
func1() = 100 ; 相当于 10 = 100; //err
func2() = 100 ; 相当于 a2 = 100;//ok
指针引用
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
struct Teacher {
char name[64];
int age;
};
//二级指针
int getTeacher(Teacher **p) {
Teacher *tmp = NULL;
if (p == NULL) {
return -1;
}
tmp = (Teacher *)malloc(sizeof(Teacher));
if (tmp == NULL) {
return -2;
}
tmp->age = 28;
strcpy(tmp->name,"aaa");
*p = tmp;
return 0;
}
//指针的引用 做函数参数 Teacher*看作一个整体 一种引用的类型
int getTeacher2(Teacher* &myp) {
//给myp赋值,相当于给main函数中的pT2赋值
myp = (Teacher*)malloc(sizeof(Teacher));
if (myp == NULL) {
return -1;
}
myp->age = 30;
strcpy(myp->name, "bbb");
return 0;
}
void FreeTeacher(Teacher **p) {
if (p == NULL) {
return;
}
Teacher *tp = *p;
if (tp != NULL) {
free(tp);
*p = NULL;
}
}
void FreeTeacher2(Teacher* &myp) {
if (myp != NULL) {
free(myp);
myp = NULL;
}
}
int main() {
Teacher *pT1 = NULL;
getTeacher(&pT1);
cout << "name:" << pT1->name << " ";
cout << "age:" << pT1->age << endl;
FreeTeacher(&pT1);
Teacher *pT2 = NULL;
getTeacher2(pT2);
cout << "name:" << pT2->name << " ";
cout << "age:" << pT2->age << endl;
FreeTeacher2(pT2);
return 0;
}
const 引用
(1)const 对象的引用必须是 const 的,将普通引用绑定到 const 对象是不合法的。
const int a=1;
int &b=a; 这种写法是不合法的,编译不过。
应改为:
const int a=1;
const int &b=a;
(2)const 引用可使用相关类型的对象(常量,非同类型的变量或表达式)初始化。这个是 const引用与普通引用最大的区别。
const int &a=2; 是合法的。
double x=3.14;
const int &b=a; 也是合法的。
const引用的目的是,禁止通过修改引用值来改变被引用的对象。const引用的初始化特性较为微妙,
输出结果为:
3 3.14
3 4.14
因为 ref 是const的,在初始化的过程中已经给定值,不允许修改。而被引用的对象是val,是非const 的,所以 val 的修改并未影响 ref 的值,而 ref2 的值发生了相应的改变。
inline内联函数
宏函数 的特点是内嵌到调用代码中去,避免了 函数调用 的开销。但是由于宏函数的处理发生在预处理阶段,缺失了语法检测 和有可能带来的语意差错。
C++提供了 inline 关键字,实现了真正的内嵌。
特点:
1)内联函数声明时inline关键字必须和函数定义结合在一起,否则编译器会直 接忽略内联请求
2)C++编译器直接将函数体插入在函数调用的地方 。
3)内联函数没有普通函数调用时的额外开销(压栈,跳转,返回)。
4)内联函数是一种特殊的函数,具有普通函数的特征(参数检查,返回类型 等)。
5)内联函数由 编译器处理,直接将编译后的函数体插入调用的地方,
宏代码片段 由 预处理器处理,进行简单的文本替换,没有任何编译过程。
6)C++中内联编译的限制:
不能存在任何形式的循环语句
不能存在过多的条件判断语句
函数体不能过于庞大
不能对函数进行取址操作
函数内联声明必须在调用语句之前
7)编译器对于内联函数的限制并不是绝对的,内联函数相对于普通函数的优势只是省去了函数调用时压栈,跳转和返回的开销。因此,当函数体的执行开销远大于压栈,跳转和返回所用的开销时,那么内联将无意义。
内联函数vs宏函数
宏函数:
优点: 内嵌代码,辟免压栈与出栈的开销
缺点: 代码替换,易使⽣生成代码体积变⼤大,易产⽣生逻辑错误
内联函数:
默认参数和占位参数
通常情况下,函数在调用时,形参从实参那里取得值。对于多次调用同一函数同一实参时,C++给出了更简单的处理办法。给形参以默认值,这样就不用从实参那里取值了
单个默认参数
多个默认参数
编译器是从右往左读取
默认参数规则
只有参数列表后面部分的参数才可以提供默认参数值
一旦在一个函数调用中开始使用默认参数值,那么这个参数后的所有参数都必须使用默认参数值
占位参数