标准C++语言-C与C++的区别

一、C++介绍

  • 发明起因:Bjarne Stroustrup,1979年4月在贝尔实验室分析UNIX操作系统分部内核流量分析时,希望有一种有效的更加模块化的工具
  • 发明过程
    • 1979年10月完成了预处理器Cpre,为C增加了类机制,也就是面向对象
    • 1983年完成了C++的第一个版本,C with classes(C++)
  • C++与C的不同点
    • C++完全兼容C的所有内容
    • 支持面向对象编程思想
    • 支持运算符、函数重载
    • 支持泛型编程、模板
    • 支持异常处理
    • 类型检查严格

二、第一个C++程序

  • 文件扩展名
    • .cpp / .cc / .C / .cxx
  • 编译器
    • g++
      • 大多数系统需要额外安装
      • ubuntu系统下的安装命令
        • sudo apt-get update
        • sudo apt-get install g++
    • gcc
      • 可以继续使用但需要增加参数 -xC++ / -lstdc++
  • 头文件
    • #include <iostream>
    • #include <stdio.h>可以继续使用
    • #include <cstdio>也可以使用
  • 输入/输出
    • cout << 输出数据
    • cin >> 输入数据
    • cout / cin 会自动识别类型
    • scanf / printf 可以继续使用
    • 注意:cout和cin是标准库类对象,而scanf/printf是标准库函数。
  • 增加了自己的名字空间
    • std:: cout
    • using namespace std;
    • 所有的标准类型、对象、函数都位于std命令空间中

三、名字空间

  • 为什么需要名字空间
    • 为了解决命名冲突(函数名、全局变量、结构、联合、枚举、类),需要名字空间对这些命名进行逻辑空间划分(并不是物理单元的划分)
    • 在C++中经常使用使用多个独立开发的库来完成项目,由于库的作者或开发人员根本没有见过面,因此命名冲突再所难免,C++之父为防止命名冲突给C++设计一个名字空间的机制
  • 什么是名字空间
    • 通过使用namespace XXX把库汇总的变量、函数、类型、结构等包含在名字空间之中,形成自己的作用域。
    • namespace XXX {
      }// 没有分号
    • 注意
      • 名字空间是标识符,在同一作用域下不能重名
      • 同名的名字空间自动合并(为了声明和定义分开写)
      • 同名的名字空间中如果有重名的依然会命名冲突
  • 名字空间的使用方法
    • :: 域限定符
    • 空间名 :: 标识符 // 使用麻烦,但是非常安全
    • using namespace 空间名
      • 把空间中定义的标识符导入到当前代码中,(不建议这样使用)
  • 无名名字空间
    • 不属于任何名字空间标识符(无名名字空间)
    • 无名名字空间中的成员使用 ::标识符 进行访问
    • 可以使用无名名字空间访问被屏蔽全局变量
  • 名字空间嵌套
    • 名字空间内部可以再定义名字空间
    • 内层名字空间与外层的名字空间的成员,可以重名,内层会屏蔽外层的同名标识符
    • 多层名字空间在使用时逐层分解
n1::n2::n3::num;
	namespace n1
	{
		int num = 1;
		namespace n2
		{
			int num = 2;
			namespace n3
			{
				int num = 3;
			}
		}
	}
  • 名字空间的别名
    • 由于名字空间可以嵌套,会导致在使用内层成员时过于麻烦,则可以给名字空间取别名来解决。
    • namespace n123 = n1::n2::n3;

四、C++的结构

  • 不再需要 typedef,定义结构变量时,可以省略struct关键字
  • 成员可以使函数(成员函数),在成员函数中可以直接访问成员变量,不需要.或->(C的结构成员可以使函数指针)
  • 有一些隐藏的成员函数(构造、析构、拷贝构造、赋值构造)
  • 可以继承,可以设置成员的访问限制(面向对象)

五、C++的联合

  • 不再需要 typedef,定义结构变量时,可以省略union关键字
  • 成员可以使函数(成员函数),在成员函数中可以直接访问成员变量,不需要.或->(C的结构成员可以使函数指针)
  • 有一些隐藏的成员函数(构造、析构、拷贝构造、赋值构造)

六、C++的枚举

  • 定义、使用方法与C语言基本一致。
  • 类型检查比C语言更严格。

七、C++的bool类型

  • C++具有真正的布尔类型,不需要额外头文件,(C语言中需要额外加stdbool.h
  • C++中,true / false 是关键字,C语言中不是关键字
  • C++中,true / false 是1字节,C语言中是4字节

八、C++的void*

  • C语言中void* 可以与任意类型的指针,自动转换
  • C++中void* 不能给其它类型的指针直接赋值,必须强制类型转换,但其它类型的指针可以自动给void* 赋值
  • C++为什么这样修改void*?
    • 为了更安全,所以C++类型检查更严格。
    • C++可以自动识别类型,对万能指针的需求不再那么强烈。

九、操作符别名

  • 某些特殊语言的键没有~,&符号,所以C++标准委员会为了让C++更委竞争力,为符号定义了一此别名,让这些小语种也可以愉快编写C++代码。
	and		=		&&
	or		=		||
	not		=		!
	{		=		<%
	}		=		%>
	#		=		%

十、C++的字符串

C:\Users\93792\Desktop\指针信息\文档资料\C++中的字符串类.md

十一、函数重载

  • 函数重载

    • 在同一作用域下,函数名相同,参数列表不同的函数,构成重载关系
  • 重载实现的机制

    • C++代码在编译时,经历了函数名称换名字的过程
    • 如果两个函数名真的一模一样,一定会起冲突
  • extern "C" {}

    • 告诉C++编译器按照C语言的方式声明函数,这样C++就可以调用C编译器编译出的函数了
    • C++目标文件可以与C目标文件合并生成可执行程序
    • 如果C想调用C++编译出的函数,需要将C++函数的定义用extern "C"包括一下。
  • 重载作用域

    • 函数的重载关系发生在同一作用域,不同作用域下的同名函数构成隐藏关系
  • 重载解析

    • 当函数调用时,编辑器根据实参的类型和形参的匹配情况,选择一个确定的重载版本
    • 实参的类型和形参的匹配情况有三种
      • 编译器找到与实参最佳的匹配函数,编译器将生成调用代码
      • 编译器找不到匹配的函数,编辑器会给出错误信息
      • 编辑器找到多个匹配函数,但没有一个最佳的,这种错误叫做二义性
    • 在大多数情况下,编译器都能找到一个最佳的版本,但是如果没有,编译器会进行类型提升,则备选函数中会产生多种版本
  • 确定重载函数的三个步骤

    • 候选函数
      • 确定所有可调用函数的集合(函数名、作用域)
    • 选择可行性函数
      • 从候选函数选择一个或多个函数(参数个数相同、而且通过类型提升实参可被隐式转换为形参)
    • 寻找最佳匹配
      • 优选每个参数都完全匹配的方案(参数完全匹配的个数、浪费内存的字节数越少)
  • const对函数重载的影响

  • 指针类型对函数重载的影响

    • C++函数在编译时,形参如果类型是指针,编译时函数名中会追加Px

十二、默认形参

  • C++中函数的形参可以设置默认值,调用函数,如果没有提供实参,则使用默认形参
  • 如果形参只有一部分设置了默认形参,则必须靠右排列
  • 函数的默认形参是在编译阶段确定的,因此只能使用常量、常量表达式、全局变量数据作为默认值
  • 如果函数的声明和定义分开,函数的默认形参应该只写在函数的声明
  • 默认形参会对函数重载造成影响,设置默认形参时一定要慎重

十三、内联函数

  • 普通函数调用时是生成调用指令(跳转),然后当代码执行到调用位置是跳转到函数所在的代码段中执行
  • 内联函数是把函数编译好的二进制指令直接复制到函数的调用位置
  • 内联函数的优点是提高程序的运行速度(因为没有跳转也不需要返回),但可执行文件增大(冗余)
  • 内联分为显式内联和隐式内联(内联函数介绍)
    • 显式内联:在函数前,inline(C语言C99标准也支持)
    • 隐式内联:结构、类中内部直接定义的成员函数,则该类型函数会被优化成内联函数
  • 宏函数在调用时会把函数体直接替换到调用位置,与内联函数一样也是使用空间来换取时间,所以宏函数与内联的区别(优缺点)?
    • 宏函数不是真正的函数,只是代码的替换,不会有参数压栈、出栈以及返回值,不会检查参数类型,因此所有类型都可以使用,但是会产生安全隐患
    • 内联函数是真正的函数,被调用时会进行传参,存在压栈、出栈以及返回值,并且严格检查参数类型,缺点是不够通用,只使用一种类型
  • 内联函数使用的方法
    • 内联会造成可执行文件变大,并增加内存开销
    • 适合频繁调用的简单函数
    • 不适合调用比较少的复杂函数(调用后不会提高性能,不足以抵消牺牲空间带来的损失)
    • 带有递归特性和动态绑定特性的函数,无法实施内联,因此编译器会忽略声明部分的inline关键字

十四、引用

  • 引用就是取艺名
  • 引用的基本特性
    • 引用就是取别名,声明一个标识符为引用,声明一个标识符为引用,就表示该标识符是另一个对象的外号
    • 引用必须初始化,不存在空引用,可以使用悬空引用(变量没了,名还在)
    • 可以引用无名对象和临时对象,但必须使用常引用
    • 引用不能更换目标(引用一旦完成了定义和初始化就和普通变量名一样,它就代表了目标,不能再引用其他目标)
    • const 添加笔记
  • 引用型参数
    • 引用当做函数的参数能达到指针的效果,不仅不具备指针的危险性,还比指针方便
    • 引用可以实现函数间的共享变量,是否引用由被调函数决定
    • 提高传递参数效率,引用是指增加一条标识符与内存之间的绑定(映射)指针则至少需要4字节内存
  • 引用型返回值
    • 不允许返回局部变量的引用,会造成悬空引用
    • 如果返回值是一个临时对象(右值)如果要使用引用接收的话,必须使用常引用
  • 注意
    • C++中的引用是一种取别名的机制,而C语言中的指针是一种数据类型(代表内存编号的无符号整数)
  • 练习
    • 练习1:实现一个C++版本的swap函数

十五、C++的内存管理

  • new/delete C++具备申请/释放堆内存功能的运算符
    • 相当于C语言中的malloc/free
    • new 类型;会自动计算类型所需要的字节数,然后从堆分配对应字节数的内存,并返回内存的首地址(具备类型)
    • delete 指针; 会自动释放堆内存
    • 注意:new/delete 和 malloc/free 不能混用,new/delete会自动调用构造/析构函数
  • 数组的分配与释放
    • new 类型 [n];n表示数组长度,类、结构会自动调用n次构造函数
    • delete [] 指针:通过new[] 分配的内存,必须通过delete[] 释放
    • new[] 返回值前4个字节中存放数组的长度
  • 重复释放
    • delete/delete[] 不能重复释放同一块内存
    • delete/delete[] 释放野指针的后果不确定,但释放空指针是安全的
  • 内存分配失败
    • 当分配的内存过大,没有能达到需求的整块内存时就会抛出异常
  • new/delete与C语言的malloc区别
区别身份参数返回值调用构造出错
new/delete运算符类型(自动计算)带类型的地址自动调用抛异常
malloc标准库函数字节数(手动计算)void*地址不能调用构造/析构函数返回NULL
  • new/delete与C语言的malloc相同点
    • 都能管理堆内存
    • 不能重复释放
    • 可以释放NULL
  • 注意:在C++中尽量使用引用new/delete
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值