- C++:面向对象的程序设计语言
- 多态
- 封装
- 继承
- C++增加的最重要的机制(3个):
- 类
- 函数重载
- 操作符重载
- C++引入了新的数据类型:bool变量:true和false
- C++的输入cin和输出cout
- 引用头文件
#include <iostream> #using namespace std;
- 常用的I/O流类操作函数:
- 引用iomanip:#include
- setw:设置场宽
- setprecision:设置输出的浮点数位数
- seriosflags:设置对齐方式、进制、精度和大小写
- hex/oct/dec:十六、八、二进制输出
- C++的内联函数:
- 目的:提高执行效率
- 与define类似,将出现函数名的位置用函数体替换
- C++动态内存分配:
- 内存申请:new
int *p = new int(10);//分配一个内存单元,赋初值为10 int *pt = new int[10];//分配10个int单元 int **q = new int*[10];//分配10个int指针单元
- 内存释放:delete
delete p; delete []pt; delete []q;
- C++提供了传递变量地址的机制
- C的参数传递只是传值
- C++在函数头中要传地址的变量前增加&--引用
- 引用:一种特殊类型的变量,可以认为给变量起别名
- 优点:
- 简化程序书写
- 提高程序执行效率
- 类的复制构造函数使用引用方式传变量地址
- C++提供类型修饰符const
- const:不可修改的量,不能给该变量赋值 void swap(int &a, const int &b){……} const A = {, , ,} //常对象
- C++的作用域与可见性
- C语言有局部变量和全局变量
- C++为了实现能够同时访问同名的局部变量和全局变量
- 作用域操作符 ::
- C++的缺省函数:
- 函数声明中,为一个或多个参数指定缺省值
- C++的数据抽象:模板操作
- 数据抽象:将数据类型与操作分开
- 栈操作:操作时不考虑对象的类型
- 模板:适用于任何数据类型的栈操作
- 函数重载:
- 定义:
- 允许函数名相同
- 对函数返回值类型是否相同没有要求
- 函数参数类型和个数不能完全一样
- 编译系统通过静态绑定确定函数到底是哪个:
- 函数参数个数不同时,由参数个数决定
- 参数个数相同时,由实参类型决定
- 如果找不到个数相同、实参类型也相同的函数,系统提示出错
- 调用二义性函数重载与缺省函数:
- 函数1:double f(double x)
- 函数2:double f(double x, double y=0)
- 函数2有缺省值,因而调用f(1.0)时编译会出错,对重载函数的调用不明确
- 定义:
- 关于类的说明:
- 类是对象的抽象,对象是类的实例。
- 类是抽象的,不占用内存
- 类不是类型,是对数据和数据操作函数的封装
- 类的成员及成员函数:
- 成员变量:
- 私有成员:private
- 公有成员:public
- 成员函数:主函数只能通过成员函数间接访问类的私有成员
- 构造函数/析构函数:
- 构造函数:与类同名的函数(只能隐式自动调用)
- 析构函数:~+类名的函数(只能隐式自动调用)
- 程序员未定义两个函数时,编译器自动生成两个函数
- 注意:析构的顺序与构造的顺序完全相反、一一对应!
- 内联构造函数:
- 构造函数前加inline
- 或函数体放在类内,自动成为内联构造函数
- 复制构造函数:
- 特殊的构造函数:形参是类对象的引用
- 作用:使用已经存在的对象,构造并初始化同类的新对象
- 浅复制:两个变量指向同一块内存,结构体整体赋值属于浅复制
- 深复制:对对象指针变量所指的内存申请新的内存,并进行赋值
- 常成员函数:
- 函数名()之后添加修饰符const
- mutable关键字,在常成员函数中给特定成员变量可以修改的功能:在定义前增加mutable
- 静态成员:
- 功能:在多个对象之间共享数据、传递信息
- 静态成员在整个程序中只有一个
- 不同类的不同对象访问唯一的一个静态成员
- 静态成员函数:只存取静态成员,在整个程序中也只有一个
- 成员变量:
- 类的一些重要特性:
- 友元机制;
- 功能:让不是本对象成员函数的其他函数能够直接访问私有成员
- 友元函数必须在类中依次列出
- 注意:
- 友元关系不能被继承。
- 友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元
- 友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元
- 嵌套类:
- 在一个类A中声明另一个类B
- 使用B类需要增加前缀变为A::B
- 类的前向引用:有些类未先定义就被其他类调用,因而需要提前声明一下类的符号
- 类的this指针:
- 成员函数可以访问到对象本身
- this指针指向该成员函数正在操作的对象
- this指针只能在成员函数内调用
- this指针不能被更新,属于常指针
- 类的组合;
- 类的成员数据是另一个类的对象
- 类的构造函数先执行内嵌对象的构造函数,在执行本类的构造函数,析构顺序与此相反
- 类的实例:对象、静态对象数组、动态对象数组(new)
- new:申请动态对象,触发类的构造函数
- delete:释放动态内存,触发类的析构函数
- 友元机制;
- 单链表:
- 特点:
- 每个元素由结点构成
- 具有线性结构
- 结点可以不连续存储
- 单链表具有扩充性
- 单链表类的定义:
- 链表结点类:ListNode
- 链表类
- 特点:
- 操作符重载:
-
定义:C++允许将原来的操作符加入新的含义
-
原则:
- 操作符必须已有,不能自己定义
- 操作符重载不能改变原运算符的运算优先级和操作数个数
- 可重载的操作符:45个
- 不可重载的操作符:5个:.、.*、::、?:、sizeof
-
编译系统对重载运算符的选择:
- 操作对象的类型决定操作符的语义
-
操作符重载函数由两种形式:
- 重载为类的成员函数:形参个数是操作符操作数个数减1
- 重载为类的友元函数:形参个数与操作符操作数相同
-
提高执行效率:将重载运算符函数的参数改为引用方式,减少函数调用,可以加上const修饰符避免引用的副作用
-
单目操作符的友元函数:将++操作符的友元函数参数改为非引用方式
-
特殊操作符的重载:
- =:默认的=是浅复制,如果想要深复制,需要对=进行操作符重载
- <<:C语言为左移,C++重载为流插入运算符,用于输出;重载是只能将<<和>>重载为类的友元函数,并且参数和返回值都必须是引用方式
-
强制类型转换:先进行类型的强制转换,再进行运算
-
C++的参数传递与C语言同样是自右向左
-
- 定义:
- 继承:保持已有类的特性而构造新类
- 派生:在已有类的基础上新增自己的特性
- 优点:
- 自动为一个类提供来自另一个类的操作和数据结构
- 重用利用已有的资源,实现代码复用
- 类的继承
- 三种继承方式:
- 公有继承
- 保护继承
- 私有继承
class Rectangle:public Shape{……}
- 继承的访问控制:
- 公有继承:派生类的成员函数只能访问基类中具有公有访问特性的成员或成员函数
- 私有继承:基类的任何性质的成员都是派生类的私有成员;派生类的成员函数可以直接访问基类的公有和保护成员
- 友元与继承:将派生类声明为基类的友元,则可以直接访问基类的私有成员
- 成员名限定:派生类和基类可以声明同名的成员,在派生类中访问时,编译器默认是派生类的成员
- 保护成员:protected
- 对于基类,类似与private
- 对于派生类,类似于public
- 派生类可以直接访问基类的保护成员,但不能直接访问基类的私有成员
- 除了派生类其他类不能直接访问A的保护成员 <<<<<<< HEAD
- 带基类内嵌对象成员的派生类:
- 例:Line类的基类是Point,Line又内嵌Point类
- 动态绑定:程序运行时进行的绑定
- 延迟到程序运行时进行动态绑定,由this指针决定调用哪一个同名函数
- 重名的成员函数前加virtual
- 多态类:基类和派生类多个函数名相同且参数个数和参数类型也完全相同的成员函数(不是函数重载)
- 虚函数:virtual修饰的成员函数
- 纯虚函数:
- 定义:虚函数在函数名之后直接赋值为0,无函数体
- 例:抽象类
class Figure{ //Figure是一个抽象类 public: virtual double getArea( )=0; //纯虚函数 }
- 纯虚函数一般是抽象类的成员函数,抽象类无成员,因而无法实例化
- 虚析构函数:
- 没有虚构造函数
- 虚析构函数是C++中唯一的函数名不同的虚函数族
- 多继承:从两个和两个以上的基类中派生
- 第一种:A→B→C→D
- D的构造函数只能使用C的构造函数,而不能使用A和B的
- D的析构函数析构时,先析构D,再调用C的析构函数,析构C,再依次调用B和A的析构函数进行析构
- 第二种:A,B,C→D
- D同时继承A,B,C,继承的方式也可以不相同
- 构造顺序ABCD
- 析构顺序DCBA
- 问题:多继承的二义性:在访问基类的成员时,如果重名,需要写清是哪个基类的成员
- 第一种:A→B→C→D
- 虚基类:
- B,C都继承A,D继承B和C,因而D保留了A的两个副本
- 虚基类使得派生类D只保留1个A的副本
class A class B:virtual public A class C:virtual public A class D:public B, public C
- 三种继承方式:
- 模板:参数化多态性
- 定义:将一段程序处理对象的类型参数化,不同类型的对象可以也用同一段程序处理,该程序称为一个模板
- 目的:
- 避免实现相同功能写过个重载函数
- 模板只是简化代码书写,不能提高程序运行效率
- C++模板主要针对函数和类:
- 函数模板:调用函数模板时,单独用模板实参说明模板参数类型
template <typename T> T abs(T a) { return a<0 ? -a : a; }
template <class X, class Y, class Z> Z fun(X x, Y y) { return x+y; } fun<int, long, double>(a, b);//调用格式
- 类模板:
#include <iostream> using namespace std; template <class T> class Stack { // 栈的类模板 public: Stack(int size); virtual ~Stack( ); void Push(const T &e); const T &Pop( ); const T &Peek( ) const; bool IsEmpty( ) const; private: T *buff; int max; int top; }; template <class T> Stack <T>::Stack(int size) //栈类模板的构造函数模板 { buff = new T[max=size]; top = -1; }
- 读写的另一种理解:
- 读操作:从流中提取
- 写操作:向流中插入
- 输出流:
- 标准输出:ostream
- cout标准输出
- cerr标准错误输出
- clog标准错误输出有缓冲
- 文件输出:ofstream
- open:打开方式有很多种
- close
- put:输出一个字符到输出流
- write
- seekp
- tellp
- flush
- clear
- eof、bad、fail、good等
- 字符串流类输出:ostringstream
- 标准输出:ostream
- 输入流:
- 标准输入:istream
- read:实现二进制读
- seekg:设置指针位置,便于随机读写
- tellg:返回文件当前指针位置
- ignore:跳过输入流中的n个字符
- sync:清空输入输出缓冲区,把输入丢掉,把输出打印出来
- fail:cin尝试输入某个数据失败后,使得输入流产生错误状态,函数返回值为真
- peek:预览将要读入的下一字符,不改变输入流
- putback:将一个字符放回输入流,放回的字符数不能超过读入的字符数
- unget:将最近读入的一个字符放回输入流
- 文件输入:ifstream
- 字符串输入:istringstream
- 标准输入:istream
- 描述:出现异常时,被执行的函数终止,控制权从函数返回,返回点是调用函数所指定的地点
- 目的:容错、提高程序鲁棒性
抛出异常: throw 表达式; 捕获异常: try { 函数调用} catch (声明) 语句
- 断言:
- 断言assert是仅在Debug版本起作用的宏
- 用于检查“不应该”发生的情况
- 如果assert的参数为假,那么程序中止(一般地还会说明在什么地方引发了assert)
- assert不是函数,而是宏
- 命名空间:将不同标识符集合在一个命名作用域,解决命名冲突
- 泛型程序设计:
- 将程序写得尽可能通用,便于程序复用,开展大规模工业化软件开发
- 将算法从特定的数据结构和类型中抽象出来,使之成为通用的算法(模板)
- STL的4个基本组件:
- 容器:向量、队列、列表、集合等
- 迭代器:承接算法与容器
- 算法:C++标准库包含70多个算法
- 函数对象:算数运算、关系运算、逻辑运算三大类
- 友元与继承:
- 将派生类声明为基类的友元,则可以直接访问基类的私有成员
- 成员名限定:
- 派生类和基类可以声明同名的成员,在派生类中访问时,编译器默认是派生类的成员