C with classes : 类及派生类、公有和私有成员、类的构造和析构、友元、内联函数、赋值运算符重载等。
C++ 1.0:添加虚函数概念,函数和运算符重载,引用、常量等。
C++ 2.0:更加完善支持面向对象,新增保护成员、多重继承、对象的初始化、抽象类、静态成员以 及const成员函数。
C++ 3.0:进一步完善,引入模板,解决多重继承产生的二义性问题和相应构造和析构的处理。
C++ 98:C++标准第一个版本,绝大多数编译器都支持,得到了国际标准化组织(ISO)和美国标准化 协会认可,以模板方式重写C++标准 库,引入了STL(标准模板库).
C++ 03:C++标准第二个版本,语言特性无大改变,主要:修订错误、减少多异性。
C++ 05C++标准委员会发布了一份计数报告(Technical Report,TR1),正式更名C++0x,即:计 划在本世纪第一个10年的某个时间发布。
C++ 11:增加了许多特性,使得C++更像一种新语言,比如:正则表达式、基于范围for循环、auto 关键字、新容器、列表初始化、标准线 程库等。
C++ 14:对C++11的扩展,主要是修复C++11中漏洞以及改进,比如:泛型的lambda表达式, auto的返回值类型推导,二进制字面常量
C++ 17:在C++11上做了一些小幅改进,增加了19个新特性,比如:static_assert()的文本信息可 选,Fold表达式用于可变的模板,if和 switch语句中的初始化器等。
C++ 20: 马上出。
1.关键字
2.命名空间(一个新作用域)
为避免命名冲突,而设定的命名规则,即把变量、函数名和类等名称定义在一个命名域内,对标识符进行本地化操作。
1)定义
关键字 namespace + 命名空间名称
//定义命名空间L
namespace L
{
int a = 10;
int b = 20; //命名空间内 可以是变量、也可是函数
int add(int left, int right)
{
return left + right;
}
}
命名空间可以嵌套定义:
//定义命名空间L
namespace L
{
int a = 10;
int b = 20; //命名空间内 可以是变量、也可是函数
int add(int left, int right)
{
return left + right;
}
namespace N //N为L内的命名空间
{
int c; //使用的时候强调两次 L:N:c 即可
}
}
同一个工程中允许存在多个相同名称的命名空间 ,编译器会自动把他们和在同一个命名空间内。
2)命名空间的使用(三种方式)
加命名空间名称及作用域限定符
使用using将命名空间中成员引入
使用using namespace 命名空间名称引入
#include
using namespace std; //方式3
namespace Li
{
int a = 10;
int b = 20;
int add(int left, int right)
{
return left + right;
}
}
using Li::a; //方式2
void namespace_test()
{
cout << "a = " << a << endl;
cout << "b = " << Li::b << endl; //方式1
cout << Li::add(10, 20) << endl;
cout << "holle word!" << endl;
}
3.C++输入 & 输出(cin cout)
使用cout标准输出(控制台)和cin标准输入(键盘)时,必须包含< iostream >头文件以及std标准命名空 间。
使用C++输入输出更方便,不需增加数据格式控制,比如:整形--%d,字符--%c
编译器可自动识别输入参数类型,来调整标准输入/输出。
#include
using namespace std;
int main()
{
int a;
double b;
char c;
cin>>a;
cin>>b>>c; //输入输出时不用管参数类型
cout<
4.缺省参数
含义:是声明或定义函数时为函数的参数指定一个默认值。在调用该函数时,如果没有指定实参则采用该默 认值,否则使用指定的实 参。
void TestFunc(int a = 0) //0就是a的缺省参数
{
cout<
注:
1)半缺省参数必须从右往左依次来给出,不能间隔着给
2)缺省参数不能在函数声明和定义中同时出现
3)缺省值必须是常量或者全局变量
4)C语言不支持(编译器不支持)
5.函数重载
含义: 是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形 参列表(参数个数 或 类型 或 顺序)必须不同,常用来处理实现功能类似数据类型不同的问题。
int Add(int left, int right)
{
return left+right;
}
double Add(double left, double right)
{
return left+right;
}
long Add(long left, long right)
{
return left+right;
}
int main()
{
Add(10, 20); //函数名相同但传入的参数的类型不同
Add(10.0, 20.0); //C++可支持名字修饰的编译规则
Add(10L, 20L); //来处理相同函数不同参数类型的问题
return 0;
}
程序在编译器中的编译过程:main.c
1)预处理://宏替换、头文件展开、条件编译、去掉注释 --> 生成 main.i 文件
2)编译:// 检查语法、生成会变代码 ---> 生成 main.s 文件
3)汇编:// 把汇编代码转换成机器码 ---> 生成 main.o 文件
4)链接:// 生成可执行程序 ---> a.out
名字修饰规则:
C语言编译时对函数名只是前面加上下划线,来区分函数,所以不支持函数重载。
C++的名字修饰规则不仅针对函数名,还有函数参数的类型相比比较复杂。根据这两点来区分函数。
在不同编译器下,底层的修饰规则不同。
extern “C“:
有时候在C++工程中可能需要将某些函数按照C的风格来编译,在函数前加extern "C",意思是告诉编译器,将 该函数按照C语言规则来编译 。
extern "C" int Add(int left, int right);
int main()
{
Add(1,2); //按照c语言的方式来编译
return 0;
}
6.引用
概念:定义一个变量的引用就是给已存在的变量起个别名,等于它和最早的变量名指向同一块内存。
类型& 引用变量名(对象名) = 引用实体 ( int& b = a), 注意:引用类型必须和引用实体是同种类型的。
特性:引用在定义时必须初始化;一个变量可以有多个引用;一个引用只能作用一个实体。
引用只能指向变量,不能指向常量,引用和实体之间类型必须相同。
#include
using namespace std;
void Swap(int& left, int& right)
{
int t = left; //利用引用作为函数参数,可实现变量的交换
left = right;
right = t;
}
int main()
{
int a = 10;
int& c = a; //引用定义是必须初始化
//int& e = 10; //此句编译不过,引用不能指向常量
int b = 20;
//c = b; //一个引用只能指向一个变量
Swap(a, b);
cout << a << endl;
cout << b << endl;
return 0;
}
引用作为函数返回值时,应注意其生命周期。
int& Add(int a, int b)
{
int c = a + b;
return c;
}
int main()
{
int& ret = Add(1, 2);
Add(3, 4);
cout << "Add(1, 2) is :"<< ret <
注意:如果函数返回时,离开函数作用域后,其栈上空间已经还给系统,因此不能用栈上的空间作为引用类型 返回。如果以引用类型返回,返回值的生命周期必须不受函数的限制(即比函数生命周期长)。
使用引用作为函数参数和函数返回值时,其效率比直接传值搞得多。
引用与指针的区别:
1. 引用在定义时必须初始化,指针没有要求 ;2. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体 ;3. 没有NULL引用,但有NULL指针; 4. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4 个字节) ;5. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小 ;6. 有多级指针,但是没有多级引用; 7. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理; 8. 引用比指针使用起来相对更安全。
7.内联函数
概念:以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销, 内联函数提升程序运行 的效率。
特性 :
1. inline是一种以空间换时间的做法,省去调用函数额开销。所以代码很长或者有循环/递归的函数不适宜使 用作为内联函数。 2. inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有循环/递归等 等,编译器优化时会忽 略掉内联。 3. inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。
#include
using namespace std;
inline void f(int i); //内联函数
//只用在声明时带上函数内联
#include "F.h"
void f(int i)
{
cout << i << endl;
}
int main()
{
f(10);
return 0;
}
宏 的优缺点:
优点: 1.增强代码的复用性。 2.提高性能。
缺点: 1.不方便调试宏(因为预编译阶段进行了替换) 2.导致代码可读性差,可维护性差,容易误用。3.没有类型安全的检查 。
常见宏函数的书写:
//使用宏,写MAX比较函数
#define MAX(a, b) (a) > (b) ? (a) : (b)
//使用宏, 写add函数
#define ADD(a, b) (a) + (b)
//使用宏, 写SWAP函数
#define SWAP(a, b) \
(b) = (a) + (b); \
(a) = (b) - (a); \
(b) = (b) - (a);
宏与内联函数的区别
(1)内联函数在编译时展开,宏在预编译时展开;
(2)编译内联函数可以嵌入到目标代码,宏只是进行简单的字符串替换;
(3)内联会做类型和语法检查,而宏不具有这样的功能;
(4)inline函数是函数,而宏不是函数;
(5)宏定义处理宏参数时存在边界问题(一般参数都要用括号括起来),而内联函数定义不会出现这样的问题。
宏与函数的选择
以下情况选择宏,其他情况选择函数:
(1)用宏代表简短的表达式时;
(2)在考虑效率的时候,可以考虑用宏或者内联函数;
(3)在头文件保护(防止重复编译)的时候,如:条件编译中的#ifdef、#if defined以及assert的实现。
8.aotu关键字
C++11中:auto不再是一个储存类型指示符, 它作为一个新的类型指示符来,auto声明变量时,必须指向一个已经指定类型的变量。
int main()
{
int a = 10;
auto b = a; //auto定义变量必须对其进行初始化
//用auto声明指针类型时,用auto和auto*没什么区别
//用auto生命引用类型时则必须加&
int x = 10;
auto y = &x;
auto* z = &x;
auto& w = x;
}
注:1. auto不能作为函数的参数
2.auto不能直接用来声明数组。
3.auto不能定义类的非静态成员变量。
4.实例化模板不能使用auto作为模板参数。 auto缺点:可读性差。
9. 基于范围的for循环
基本含义:解决循环范围说明的问题。
for( : ) :分为两部分:1.第一部分是范围内用于迭代的变量。2.第二部分则表示被迭代范围。
#include
using namesapce std;
int main()
{
int array[] = {1, 2, 3, 4, 5};
for(auto& e : array)
e *= 2; //在数组的范围内实现每个数乘2
for(auto e : array)
count << e << " " << endl;
return 0;
}
注:与普通循环类型,可以用continue来结束本次循环,也可用break来跳出整个循环。
10.指针空值nullptr(C++11)
C语言中:空指针用NULL来表示,而NULL是用0定义的宏。 是int型,不合适用来表示指针。
int* p1 = NULL; int* p2 = 0; 0 和 NULL 两个是一样的东西。
C++11:使用nullptr来表示控指针,它是char型的。
int* p = nullptr; //nullptr-->(void*)类型