一、C++对C的加强
C++是对C的基础语法的扩展,面向对象(继承、封装、多态),STL等。
1、namespace
1)当使用<iostream>的时候,该头文件没有定义全局命名空间,必须使用namespace std; using namespace std; 或 std::cout
2) C++标准为了和C区别开,也为了正确使用命名空间,规定头文件不使用后缀.h
3) C++命名空间的定义: namespace name{...}
4) using namespace NameSpaceA;
5) namespace 定义可嵌套
2、“实用性”增强
C++中更强调语⾔的“实⽤性”,所有的变量都可以在需要使⽤时再定义。
3. 变量检测增强
在C语言中,重复定义多个同名的全局变量是合法的
在C++语言中,不允许定义多个同名的全局变量
在C语言中多个同名的全局变量最终会被链接到全局数据区的同一个地址空间上
4. struct类型增强
C语言中struct定义了一组变量的集合,C编译器并不认为这是一种新的类型
C++中的struct是一个新类型的定义声明
5. C++中所有变量和函数都必须有类型
C++中所有变量和函数都必须有类型
C语言中默认类型在C++中是不合法的
C中,int f(),表示返回值为int,接受任意参数的函数,int f(void),表示返回值为int的无参函数
C++更加强调类型,任意的程序元素都必须显示指明类型
6. 新增bool类型关键字
C++中的bool可取得值只有true和false,理论上bool只占一个字节,多个bool变量在一起可能会各占1bit,这取决于编译器的实现
bool类型只有true(非0)和false(0)两个值,C++编译器会在赋值时将非0转换为true,0值转换为false。
7. 三目运算符功能增强
int a = 10;
int b = 20;
(a<b?a:b) = 30; //可以为左值,C++中返回变量本身
a) C语言返回变量的值,C++语言返回变量本身
b) 注意:返回的是一个常量值,则不能作为左值使用
8. const增强
1) const基础知识
const定义常量,const意味只读
const int a;
int const b; //相同,代表一个常整型数
const int *c; //*c,指向的内存数据不能被修改
int * const d;//d,指针变量不能被修改
const int * const e; //指针和指向的内存空间,均不能被修改
【合理的利用const的好处】
1)指针做函数参数,可以有效的提高代码可读性,减少bug
2) 清楚的分清参数的输入和输出特性
int setTeacher_err(const Teacher *p)
const修饰形参的时候,在利用形参不能修改指针所指向的内存空间。
2) C语言中的“冒牌货”
const int a = 10;
int *p = (int *)&a;
*p = 10;
3) const 和 #define的相同
const int a = 1;
const int b = 2;
int array[a+b] = {0};
C++中的const修饰的,是一个真正的常量,而不是C中变量(只读),在const修饰的常量编译期间,就已经确定下来了。
4) const和#define区别
C++中的const常量类似于宏定义
不同之处:
const常量是由编译器处理的,提供类型检查和作用域检查;宏定义由预处理处理,单纯的文本替换
【总结】
C语言中的const变量是只读变量,有自己的存储空间
C++中的const常量,可能分配空间,也可能不分配空间
const常量为全局,并且需要在其它文件中使用,会分配存储空间
当使用&操作符,取const常量的地址时,会分配存储空间
当const int &a=10; const修饰引用时,也会分配存储空间
9. 真正的枚举
C语言中枚举本质就是整型,枚举变量可以用任意整型赋值。而C++中枚举变量,只能用被枚举出来的元素初始化。
二、C++对C语言的拓展
1. 函数重载
1.1 重载的概念
在相同的作用域的函数,有相同的函数名,而形参表不同,称为重载函数。
int max(int a,int b);
double max(double a,double b);
char* max(char* a, char* b);
编译器根据所传递的实参类型来判断调用哪个函数。
函数不能仅仅基于不同的返回值类型而实现重载。
int f(int);
float f(int);
double f(int);
2. 引用的概念
int a = 10;
int &b = a;
b称为a的引用,b是a的别名。引用变量b与变量a绑定在一起,也叫相关联。&表示引用声明符,不是取地址符。b和a占同一内存存储单元。
1)在定义一个引用时,必须同时初始化
2)当引用初始化后,只要该引用存在,它就与初始化时指向的对象相关联,不能将引用关联到其它对象
3)引用不是独立的数据类型,是复合类型,必须使其代表某一类型的对象
4)可以定义数组引用
4.引用和指针的区别
1)从内存分配上看:指针是一个实体,而引用仅是个别名。程序为指针变量分配内存区域,而引用不需要分配内存区域,它与它所绑定的对象占同一内存存储单元。
2)“sizeof引用”得到的是引用所绑定的对象的大小,而“sizeof指针”得到的是指针本身的大小。
3)引用使用时无需解引用(*),指针需要解引用
4)引用只能在定义时被初始化,之后就不能改变它和它所绑定的对象之间的联系,指针可改变指向
5. 引用作为函数参数
5.1 引用与非引用类型作为函数参数的区别
1) void swap(int a, int b); //非引用类型,赋值实现的值
2) void swap(int *a, int *b); //形参为指针类型时,形参复制的是指针所指向对象的地址,函数内部通过指针的使用,来修改指针所指向对象的值
3) void swap(int &a, int &b); //形参引用类型时,它只是实参的别名,并不是实参的副本,调用函数时,引用形参被创建,并且与相应的实参相关联,对形参的任何修改其实就是对实现的修改
5.2 使用引用形参的情况
以下两种情况优先选择引用形参:
1) 需要在函数中改变实参的值
2)大型的对象(如类对象)作为实参传递时,此时复制对象需要的时间和空间的代价都较大
以下一种情况必须使用引用形参:
1)对象无法进行复制时。(比如IO流对象)
6. 引用作为函数返回值
6.1 引用与非引用类型作为函数返回值的区别
函数的返回值是用于初始化在函数调用处创建的临时对象。
int func(int a)
{
int b = a + 10;
return b;
}
int main()
{
int c = func(10); //int temp = b; int c = temp;
}
如果返回值是非引用类型,在调用函数结束后会将函数的返回值复制给临时对象,临时对象是返回值得副本。
6.1 引用作为函数返回值时需要注意的问题
1. 函数返回引用类型时,不会复制返回值,返回的是对象本身。
2.不要返回绑定局部对象的引用,函数调用结束,局部对象被释放,返回的引用就会指向不确定的内存。
3.不要返回指向栈内存的指针,因为函数调用结束,局部对象被释放,返回的指针变成了指向不再存在对象的悬垂指针。
【内容回顾】
1. 引用和指针的区别?
引用不需要额外空间,指针需要
引用不用解引用,指针需要
引用不可指向其它位置,指针可以
引用初始化时必须指向对象,指针可以不指向
2. 可以定义数组引用吗?
可以
3.什么情形需要引用形参?
大型程序,类似swap交换的时候
4.函数返回值为引用类型时,需要注意哪些问题?
不能返回临时变量的引用
不能指向一个栈空间,马上被释放的变量和栈空间是不行的。