第一章
C++的特点:
1.支持四种编程范式:面向过程、面向对象、泛型编程、函数式编程
2.可复用、可扩展、可维护、灵活性好
3.适合开发大型引用程序
头文件:不带.H
math.h cmath
string.h cstring
关键字都是小写
命名空间 解决命名冲突
const
char*
const char*、char const*常量指针
char* const 指针常量
//*前面的是修饰数据类型的,*后面的是修饰指针的.比如const char* ,const在*前面说明是修饰数据类型char的,即表明指针所指向的地址可以改变,但数据不能改变因为被const修饰了
而char*const,const在*后面说明修饰的是指针,即指针所指向的地址不能改变,因为指针被const修饰了,但数据可以改变因为char没有被const修饰
char arr[10]; arr实际类型是char*const
引用
别名,一般不定义局部变量的引用,用在函数之间
函数参数:
实参就是形参
参数类型是常引用类型
const vector<int>&
常引用是常对象,常对象只能调用调用常函数
重载自定义类型的operator<,常函数
函数返回值:
不能返回局部变量的引用
ostream& operator<<(ostream& out,const...&){return out;}
函数作为左值
return *this
new/delete
堆
一个进程只有一个堆
手动分配、手动回收
不能通过变量访问,只能通过指针间接访问
栈
每个函数的每一次运行,都会有一个独立的栈,放局部变量
自动分配、自动回收
通过局部变量访问
int* p =new int;
new/delete和malloc/free不能混用
new/delete和new[]/delete[]是两对运算符
定义变长数组
int len=100;//变量
int* p=new int[len];//变长数组
p[i]和*(p+i)是等价的
RALL 资源获取即初始化
Resource Acquisitionnis Initialization
在构造函数中new,在析构函数中delete
函数参数的默认值
int add(int a= 1,int b=2,int c=3){return a+b+c};
add(1);
add(1,1);
add(1,1,1);
从右往左连续定义
只能写一次,优先写在声明中
同时使用参数默认值和重载,要防止二义性
同名函数
重载、隐藏、覆盖
同一作用域:重载,参数列表不同
int add(int a,int b);
int add(int x,int y);//不构成重载因为参数列表相同了
父类子类:隐藏或覆盖
覆盖:虚函数virtual,原型一致
不是覆盖都是隐藏
class Base{
int foo(int);//1
int foo(int,int);//2
};
class Derived:public Base{
int foo(int,int);//3
};
Drived d;
d.foo(1,2);//3
d.foo(1);//错误
d.Base::foo(1);//1
d.Base::foo(1,2);//2
初始化
int a = 100//c语言
int a(100);//经典C++
int a{100};//现代C++
class Foo{};
Foo a(1);//1
Foo a=1;//1
Foo a{1};//1
Foo* pf,//0
Foo pf[10]//10
Foo* paf[10];//0
//共调用13次构造函数
第二章
面向对象三大特征
封装,隐藏内部实现
继承,复用现有代码
多态,改写对象行为
成员:成员变量(名词性的属性)、成员函数(动词性的行为)
成员变量可以是自身类型的指针、引用
class Foo{Foo* pf;Foo& rf;}
class Foo{Foo f;}//错误的
成员函数:构造函数/析构函数、Seter/Geter
构造函数 析构函数
1.命名 与类同名 与类同名前面加~
2.返回值和函数类型 不能有函数类型和返回值,void、return都没有
3.参数列表 有参数,可以重载 没有参数,不能重载
4.虚函数 不能是虚函数 父类的析构函数一般都是虚析构函数
访问权限
不可访问成员 冻结财产
私有成员 个人财产
保护成员 家族财产
公有成员 公共财产
默认访问权限:class是私有,struct是公有
继承方式对访问权限的影响
私有、不可访问都是不可访问
继承方式决定最高访问权限
默认继承方式:私有,最常用的继承方式是:公有
成员变量一般是保护成员
作用:
构造函数:创建和初始化对象
析构函数:释放对象
默认构造函数
系统提供,无参
无参构造函数
Foo*pb=new Foo;
Foo f;
Foo af[10];
带参构造函数
Foo*pb = newFoo(10);
Foo f(10);
Foo af[3]{1,2,3};
拷贝构造函数
一个参数,自身类型的引用(一般是常引用)
默认拷贝构造函数
系统提供
Foo a;
Foo b =a; Foo b(a);
类型转换构造函数
一个参数,不是自身类型、也不是自身类型的引用
class Foo{
Foo(int x);
};
Foo a =10;
构造函数的参数不能是自身类型
非静态成员函数,有一个默认的this指针
深拷贝和浅拷贝
指针类型的成员变量
没有*,bit-by-bit就够了
两个对象的两个指针指向同一端内存
class Foo{
T*p;
Foo(const Foo&other){
计算other.p指向内存的大小
p=new T(大小)
数据的复制
}
};
常const
class Foo{
void F() const;//常函数
};
void Foo::F() const{}
static Foo{
void F() const;
};
void Foo::F(){}//static函数实现时const不用写,与class相反
静态static
静态成员变量:必须类外初始化,不需要再写static
静态成员函数:
没有this指针,
静态成员函数只能使用静态成员
静态成员属于类
两种调用方式,对象调用、类名调用
没有对象,也可以调用静态成员函数
友元friend
不是成员函数,与访问权限无关
可以访问类的所有成员
类不能访问友元函数的成员
单向性、不能传递、不能继承
第三章运算符重载
本质是函数重载,函数名是operator运算符
作用:让代码简洁
不是所有的运算符都能被重载
两种形式:成员函数、全局函数(往往被声明为友元)
重载为成员函数:
左操作数必须是当前类型
一元运算符不需要参数,当前对象就是操作数
二元运算符只要一个参数,代表右操作数,当前对象是左操作数
类型转换
类型转换构造函数:
只有一个参数,并且不是自身类型、自身类型的引用
类型转换运算符:
operator 目标类型();
operator float();
static_cast<目标类型>(表达式);
explicit关键字,避免默认类型转换
函数运算符()的重载
函数指针
仿函数
内置仿函数
lambda表达式
自定义类型重载<运算符
sort函数要求二元谓词
第四章继承和派生
1.基类、派生类、Base,Derived
2.C++支持多继承
3.UML的类图,三格矩形,箭头表示继承(子类指向父类)
派生类对象
类型兼容
赋值
Base b;
Derived d;
d=b;错误的
b=d;正确的
Base*pb = new Derived;
Base& rb=d;
第五章 多态和虚函数
virtual,实现机制,虚函数表,实现多态是以牺牲性能为代价
三种同名函数:重载、隐藏、覆盖
调用机制:重载取决于参数列表、隐藏取决于变量类型、覆盖取决于对象类型
多态:调用同名函数因为上下文不同会有不同的实现的一种机制
两种多态:静态多态,函数重载,编译阶段完成;
需要花费更多的编译时间,但是不会降低运行速度
动态多态,继承+虚函数,运行阶段完成
动态多态以牺牲运行速度为代价
纯虚函数和抽象类
纯虚函数:虚函数 函数体 =0
定义了纯虚函数的类,叫做抽象类
java:只有纯虚函数的类叫做接口interface
抽象类不能实例化对象
RTTI
typeid
dynamic_cast
第六章模板
模板编程也叫泛型编程
目的:代码复用
函数模板=》模板函数
函数模板可以实例化成多个模板函数(传递了多少种类型,就会实例化多少个模板函数)
高级语言:1个函数模板,经过编译后,在二进制代码中,会有多个对应的模板函数
template<typename T>//没有分号
T add(T a,T b){return a+b}
add(1,2);
add(3,4);
add(1.2,3.4);
在没有二义性的情况下,函数模板的类型参数可以省略
add<int>(1,2); =>add(1,2)
add(1,2.3f) //二义性
类模板=》模板类
不能隐式调用
第七章STL
standerd template library标准模板库
三大核心:容器、迭代器、算法
六大组件:、、、适配器、仿函数、分配器
常用容器的内部实现:
vector 动态数组 下标运算法不支持插入
list 双向链表 没有下标访问运算符
map、set红黑树
push_back push_front
pop_back pop_front
begin()、end()、 [)左闭右开
vector\array\dque
list
map 插入删除两种功能
基于for循环
vector:
vector<int>vi
vector<int>vi(10)
vector<int>vi(10,99)
迭代器的两种方式(常规、自动推导)
任意类型的迭代器原始类型要写出来
map<int,int>m 容器原始类型->map<int,int>::ierator itr;
auto itr = m.begin();//自动推导
用到的算法: sort,第三个参数是二元谓词 //大题要考 random_shuffle,洗牌 generate_n(back_insertot(),n,[](){});向容器插入n个元素 copy(ostream_iterator<int>(cout,间隔符)); accumulate(,,0);//参数表示范围,初始值 累加和
第八章I/O
#include <fstream>
fstream ifs("data.txt",ios::in);//文本文件
while(!ifs.eof()ifs>>容器;
ifss.close();
ifstream& operator>>(ifstream& in,容器的引用){
.../
return in;
}
第九章异常
try catch throw (作用?)
子函数(){ //若干层调用的子函数
throw(某个类型的异常); //抛出异常
}
主函数(){ try{ 子函数的调用; } catch(类型1){} catch(类型2){} } //try catch用于捕获异常
第十章
auto自动类型推导
基于范围的for循环
lambda表达式
面向对象的知识点
编程三大原则
永远不变的是变化,以不变应万变 父类指针指向子类指针 哪些是抽象的(父类)哪些是具体的(子类)哪些是不变的哪些是变化的 封装变化点、针对接口进行编程、优先使用组合(is-a(继承和派生)、has-a(成员对象)) 设计模式的来源是建筑设计领域 策略模式、模板方法模式、工厂模式
SOLID五大原则
SRP单一职责原则 OCP开闭原则(对扩展开放,对修改关闭) LSP里氏替换原则 ISP接口隔离原则 DIP依赖倒置原则(高层模块不依赖于底层模块,二者依赖于抽象) 我用杯子喝水 我高层模块 玻璃杯底层模块
代码复用:函数、继承、组合、模板 使代码简洁的语法:重载(函数重载、运算符重载)、默认参数、 实现面向对象:继承、虚函数、父类指针指向子类对象
calss Foo{}; int main() { Fooo d; //调用一次无参构造函数 vector<Foo> mf; mf.push_back(d); //调用拷贝构造函数,用自身类型对象d初始化另一个同类型的对象 有两个d对象 }
栈里的对象 classFoo{}; main(){ Foo d1;//局部变量,对象在栈里面 Foo*pd=new Foo; delete pd; }//释放栈,释放栈里的对象,调用d1对象的析构函数,再调用pd析构
要考inline内联函数 小涵数、没有循环 void fun(){********;} main(){ #### fun(); #### fun(); }
class Foo{ public: Foo(int mm):m(mm){n=nn;} private: const int m;//常成员变量只能列表初始化 const int m=10;//经典c++不允许,但现代c++可以 };
静态成员函数只能调用静态成员 非静态成员可以调用静态成员 this 没有this
40分编程
40个空
析构函数4个特点abcd