c++
C++
1. C++概述
1.1 C++简介
c++是c的扩展,是c的超集。任何有效的c程序都是有效的c++程序。
c++可以使用已有的c程序库。
c++语言在c语言的基础上添加了面向对象编程和泛型编程的支持。
c++继承了c语言高效、简洁、快速和可移植的传统(特性)
C++编程方式:
- c的面向过程编程
- c++的面向对象编程
- c++模板的泛型编程
C语言和C++语言的关系:
c++语言实在c语言的基础上,添加了面向对象、模板等现代程序设计语言的特性而发展起来的。两者无论是从语法规则上。还是从运算符的数量和使用上,都非常相似,所以我们常常将这两门语言统称为“c/c++”
C语言和C++并不是对立的竞争关系:
1.c++是c语言的加强,是一种更好的c语言
2.c++是以c语言为基础的,并且完全兼容c语言的特性
1.2 可移植性和标准
可移植性:开发的c/c++的源代码,可以在任何安装c/c++编译器的操作系统,可以重新编译,即可运行。
标准:
- ANSI/ISO C++
- ISO/IEC 14882:1998,简称c++98
- 已有的c++特性
- 对语言进行了扩展,添加了异常、运行阶段类型识别(RTTI)、模板和标准模板库(STL)
- ISO/IEC 14482:2003,只是修复c++98的bug,没有大的改动。因此c++98也称之为c++98/c++2003
- ISO/IEC 14482:2011:c++11
2. C++初始
2.1分析C++的helloworld
#include <iostream>
using namespace std;
int main()
{
cout << "Hello World!" << endl;
return 0;
}
第一行:引入iostream
头文件,此文件包含std命名空间,和标准的输入和输出
第二行:using namespace std;使用标准的命名空间,命名空间中定义标准的变量
第四行:cout输出对象,是std命名空间的,也可以写成std::cout,cout和<<运算符组合使用,表示输出什么内容,如"Hello World!"endl
表示换行符
将main.cpp的文件内容,修改如下:
#include <stdio.h>
int main()
{
printf("Hello World!");
return 0;
}
代码可以正常运行,说明c++兼容c的语法
2.2 面向过程和面向对象
2.2.1 面向过程
面向过程编程思想的核心:功能分解,自顶向下,逐层细化(程序=数据结构+算法)
面向过程编程语言存在的主要缺点是不符合人的思维习惯,而是要用计算机的思维方式去处理问题,而且面向过程编程语言重用性低、维护困难
2.2.2 面向对象
面向对象编程(Object-Oriented Programming)以下简称 OOP 。
在面向对象中,算法与数据结构被看做是一个整体,称作对象,现实世界中任何类的对象都具有一定的熟悉和操作,也总能用数据结构与算法两者合一地来描述,所以可以用下面的等式来定义对象和程序:
对象 = 算法(方法或功能函数) + 数据结构(数组、结构体...)
程序 = 对象 + 对象 + ...
面向对象编程思想的核心:应对变化、提高复用
2.2.3 面向对象的三大特征
- 封装:可以将客观的事务抽象为类,类中封装一些数据(属性-特征)和方法(行为),可以根据需要设置数据或方法的访问权限,对于一些重要的数据设置为不可访问。
- 继承:继承所表达的是类之间相关的关系,这种关系使得对象可以继承另外一类对象的特征和能力,继承的作用:避免公用代码的重复开发,减少代码和数据冗余。
- 多态:多态可以简单概括为"一个接口,多种方法",字面意思为多种形态。多用于描述一个对象的多种形态,使用多态性必须具有继承和重写方法的前提。
3. C++对C的扩展
3.1 ::作用域运算符
可用::对被屏蔽的同名的全局变量进行访问
3.2 名字控制
在大的工程中,存在多个源文件或类,所以可能存在重名的情况。在C++提供不同方式,使得同一个名字可以具有不同的数据或功能
3.2.1 c++命名空间(namespace)
为了避免,在大规模程序的设计中,以及在程序员使用各种各样的c/c++库时,这些标识符的命名发生冲突,标准c++引入关键字namespace(命名空间/名字空间/名称空间),可以更好地控制标识符的作用域
3.2.2 namespace用法:
-
命名空间只能全局范围内定义,不能在局部定义
-
命名空间可以嵌套命名空间
-
声明和实现可分离
-
无名的命名空间只能在当前文件中使用
-
命名空间可以存在别名
-
定义namespace的语法:
namespace [名称] { 成员的声明,可以具有初始化的值; [ 内部嵌套namespace{}; ] [声明成员函数] [定义成员函数] } //实现namespace中声明的函数 函数返回值类型 命名空间的名称::声明的函数名(形参列表){ }
【无命名空间】
无名命名空间,意味着命名空间中的标识符只能在本文件内访问,相当于给这个标识符加上了static,使得其可以作为内部连接
3.2.3 using声明
using声明可使得指定的标识符(函数、变量、结构体、枚举、类)可用
语法:
using 命名空间的名称::成员名; 当前位置向下,可以直接使用成员名,即为命名空间的成员
【注意】使用了命名空间之后,可能存在名称冲突。平时使用时注意using和其它同名标识符先后顺序。
using声明碰到函数重载:using一次函数名,既可以将所有的相同名的重载函数都引入
3.2.4 using编译指令
using编译指令使整个命名空间标识符可用
【注】使用using声明或using编译指令会增加命名冲突的可能性。也就是说,如果有名称空间,并在代码中使用作用域解析运算符,则不会出现二义性。
语法:
using namespace 命名空间的名称; 当前位置向下,可以直接访问命名空间中所有的成员
3.2.5 命名空间使用
需要记住的关键问题是当引入一个全局的using编译指令时,就为改文件打开了该命名空间,它不会影响任何其他的文件,所以可以在每一个实现文件中调整对命名空间的控制
如果发现某一个实现文件中有太多的using指令或声明而产生的命名冲突,就要对该文件做个简单的改变,通过明确的限定或者using声明来消除名字冲突,这样不需要修改其他的实现文件。
3.3 全局变量检测增强
在C++中全局变量无论是声明还是定义,只能出现一次。
因此,在c++中定义全局变量时,无初始化值时,默认值为0。
3.4 C++中所有的变量和函数都必须有类型
C的自定义函数时,形参变量可以没有数据类型,即为任意类型
c++中,函数的形参变量必须指定类型。
3.5 更严格的类型转换
在C++中, 不同类型的变量之间赋值时,需要明确的类型转换。
3.6 struct类型加强
在C++中,定义结构体变量时,不用加struct。
3.7 新增bool 类型关键字
bool 类型只有两个值,true(非0值),false(0 值)
bool 类型占 1 个字节大小(操作系统最小处理数据单位是字节)。
3.8 三目运算符功能增强
C中三目运算表达返回是变量的值, 而c++中,三目运算表达式返回是变量。
3.9 C/C++中的const
const修饰的变量,只能读取,不能修改其值。
C/C++中 const 的区别:
原则上:c中的const变量,不能做为数组的个数使用, 因为数组分配的空间可能发生变化(扩大,缩小)。
gcc 99/g++11编译器: const变量可以作为数组的个数使用。
C中的const变量,在定义时,则会在内存中创建空间, 而c++不会创建,只有取一个 const 地址, 或者把它定义为 extern,则会为该 const 创建内存空间。
在 c++中,出现在所有函数之外的 const 作用于整个文件(也就是说它在该文件外不可见),默认为内部连接,c++中其他的标识符一般默认为外部连接(指向是常量区)。
默认情况下,const初始化值为常量,不会开辟空间,只是存储在符号表中。如果const变量初始化值为一个变量时,则会在内存中开辟空间
3.10 const和#define的区别
1)const变量有数据类型,而#define宏无数据类型
调用重载的函数时,传入const变量时正确的,而传入宏,是无法确认调用函数的入口
2)const变量具有作用域,而#define宏从定义开始到文件结束都是有效的
3.11 引用
引用相当于指针,在向函数传递地址时,可以使用指针,也可以使用引用。引用是c++对c的重要扩充
3.11.1 基本用法
普通变量的用法:为变量起别名,变量的引用名即和变量名操作同一个内存空间
定义引用变量时,必须给初始化值,另外,定义之后引用不能再引用其它的变量。初始值不是NULL。
引用数组的正确方式:不能直接引用数组(int &p=arr)
3.11.2 函数的参数引用
形参可以是引用,声明方式:数据类型 &形参名
函数的返回值也可以是一个引用,返回的变量不能是局部变量
如果函数返回值作为赋值语句的左值,则必须返回引用
数组引用作为函数的参数,数组名本身就是一个地址,无需再按数组的引用定义方式来定义形参
3.11.3 引用的本质
引用的本质是指针常量,初始化时必须给定初始值,因为指针不能修改
常量指针和指针常量的区别
常量指针:const int *p = &a; const修饰是*p,*p只读,p读写
指针常量:int * const p = &a; const修饰是p,p只读,*p读写
常量指针常量: const int * const p = &a; *p只读,p只读
3.11.4 指针的引用
为指针起个别名,表示为指针的指针
用法:数据类型*& 变量名=指针变量名
3.11.5 常量引用
用法:const 数据类型 & 变量名 = 其它变量或常量
【注意】
1)一般的引用不能赋值常量(字面量),但是const引用可以赋值常量
2)const引用不能修改内容(数据)
3.12 内联函数
定义函数的前面添加了inline关键字,则此函数为内联函数
内联函数只能在当前文件中使用,相当于函数前面加static
内联函数一般用于替换有参的宏,有参宏经常会出错,而且参数是无数据类型。
每一次使用内联函数时,都会像有参宏一样,展开一次(内联函数不入栈,运行效率高)
内联函数为了继承宏函数的效率,没有函数调用时的开销,然后又可以像普通函数那样使用,每次使用时都会进行参数,返回值类型的安全检查,又可以作为成员函数。
内联函数作为类的成员函数时,可以访问私有成员(数据)
内联函数的声明和定义必须在一起,否则取消内联函数性质
【说明】类中所有函数,编译器默认都是内联函数。inline修饰的函数是否为内联函数,取决于编译器。对于非inline修饰的函数,也有可能转成内联函数(体积小、功能简单的函数)。
内联函数使用时的注意事项:
1)不能存在任何形式的循环语句
2)不能存在过多的条件判断语句
3)函数体不能过于庞大
4)不能对函数进行取址操作
3.13 函数的默认值参数
c++的函数在声明时,可以设置形参的默认值,在调用函数时,形参位置没有指定实参数据时,则使用默认值
【注意】函数的默认参数从左向右,如果一个参数设置了默认参数,那么这个参数之后的参数都必须设置默认参数,如果函数声明和函数定义分开写,函数声明和函数定义不能同时设置默认参数。
3.14 函数的占位参数
c++在声明函数时,可以设置占位参数。占位参数只有参数类型声明,而没有参数名。一般情况下,在函数体内部无法使用占位参数。占位参数也可以设置默认值。
【注意】调用函数时,占位参数也需要传值
3.15 函数重载和extern"c"
1.c++支持函数的重载特性,函数重载即与函数名和参数列表相关,与函数的返回值无关。
存在多个函数名相同、参数列表不同的情况时,称之为函数重载
参数列表不同:个数不同,个数相同时类型不同或顺序不同
void f(int a);
void f(int a, int b); // f(int,int)
void f(double a,int b);
void f(int a, double b);
// void f(int b, int a); 重载检查按参数类型不同查找,f(int, int) 上面已声明了,不能再次声明。
2.由于c++可以使用c的模块中函数,当c++整个工程编译时,可能会将使用c语言编写的函数名编译成c++规则的函数名(定义的函数名前随机添加新的名称),链接程序时,可能会找不到目标函数,因此采用extern "C"
解决。