强制类型转换符
C++有四种强制类型转换符
- dynamic_cast:将基类的指针或引用安全地转换为子类的指针或引用
- const_cast:将常量指针或引用被转化成非常量的指针或引用,来修改常量
- static_cast:子类指针或引用向上转换成基类(安全),基类指针或引用向下转换成子类(不安全),基本数据类型之间的转换,空指针转换成目标类型的空指针,任何类型的表达式转换成void类型
- reinterpret_cast:用来处理无关类型之间的转换,它会产生一个新的值,这个值会有与原始参数有完全相同的比特位
指针
一级指针和二级指针
float(**a)[10];
a是一个二级指针,指向一个一维数组的指针,数组元素为float类型
double*(*b)[10];
b是一个一级指针,指向一个一维数组,数组元素为double*类型
double(*c[10])();
c是一个10个元素的数组,数组元素为指向函数类型为没有参数且返回double的函数指针
int*((*d)[10]);
同int(d)[10];d是一个一级指针,指向一个一维数组,数组元素为int*类型
long (*e)(int)
e是一个一级指针,指向函数类型为参数为int且返回long的函数指针
int (*(*f)(int, int))(int)
f是一个一级指针,指向函数类型为参数有两个int且返回一个函数指针的函数,返回的函数指针指向类型为参数为int且返回int的函数
函数指针和函数返回指针
函数指针
void (*f) ();
函数返回指针
void* f();
函数指针的使用
#include <cstdio>
int max(int x, int y)
{
return x > y ? x : y;
}
int main()
{
int max(int, int);
int (*p) (int, int) = &max;
int a, b, c, d;
scanf(“%d %d %d”, &a, &b, &c);
d = (*p) ((*p)(a, b), c);
printf(“max: %d\n”, d);
return 0;
}
const修饰指针的4种情况
const int *a = &b;
const修饰指针指向的变量,指针指向的变量不可变
int const *a = &b;
const修饰指针指向的变量,指针指向的变量不可变
int* const a = &b;
const修饰指针,指针不可变
const int* const a = &b;
指针和指针指向的变量都不可变
指针和引用的差别
非空区别
-
- 任何情况下都不能使用指向空值的引用。这意味着使用引用的代码比指针高
合法性区别
-
- 使用引用之前不需要测试合法性
- 指针则应该总是被测试,防止其为空
可修改区别
-
- 指针可以被重新赋值以指向另一个不同的对象
- 引用则总是指向在初始化时被指定的内容,以后不能改变
应用区别
-
在以下情况应该使用指针
-
- 考虑存在不指向任何对象的可能
需要能够在不同的时刻指向不同的对象
否则应该使用引用
内存大小
-
- 指针是一种存储指向变量地址的类型,需要占用空间
- 引用是变量的别名,不需要占用空间
泛型编程
泛型编程是一种基于发现高效算法的最抽象表示的编程方法。也就是以算法为起点并寻找能使其工作且有效率工作的最一般的必要条件集。
很多不同的算法都需要相同的必要条件集,并且这些必要条件有多种不同的实现方式。
泛型编程假定有某些基本法则在支配软件组件的行为,并且基于这些法则有可能设计可互操作的模块,甚至可以使用此法则去指导我们的软件设计。
STL是泛型编程的例子。
template<typename T>
const T* find(T* array, T n, T x)
{
const T* p = array;
int i;
for (i = 0; i < n; ++i)
{
if (*p == x)
{
return p;
}
}
return NULL;
}
类的访问控制
访问范围
private
-
- 该类的函数
- 该类的友元函数
- 该类的友元类
protected
-
- 该类的函数
- public继承的子类的函数
- 该类的友元函数
- 该类的友元类
public
-
- 该类的函数
- public、protected继承的子类的函数
- 该类的友元函数
- 该类的友元类
- 该类的对象
继承
继承类型
private继承
-
- 父类的protected和public变为private
protected继承
-
- 父类的public变为protected
public继承
-
- 不改变
虚继承
虚继承是面向对象编程中的一种技术,是指一个指定的基类,在继承体系结构中,将其成员数据实例共享给也从这个基类型直接或间接派生的其它类。
class Animal
{
public:
virtual void eat();
};
// Two classes virtuallyinheriting Animal:
class Mammal : public virtual Animal
{
public:
virtual voidbreathe();
};
class WingedAnimal: public virtual Animal
{
public:
virtual void flap();
};
// A bat is still awinged mammal
class Bat : public Mammal, public WingedAnimal
{
};
Bat bat;
如果不采用虚继承,调用bat.eat()是有歧义的,因为在Bat中有两个Animal基类(间接的),所以所有的Bat对象都有两个不同的Animal基类的子对象。
采用虚继承后,Bat现在有且只有一个共享的Animal部分,不再有歧义
菱形继承
上述例子不采用虚继承,就会出现菱形继承的问题,在Bat中有两个Animal基类(间接的),所以所有的Bat对象都有两个不同的Animal基类的子对象。
多重继承
多重继承指的是一个类别可以同时从多于一个父类继承行为与特征的功能。
继承优缺点
优点
- 复用性强
缺点
- 可能出现二义性(菱形继承)
面向对象
面向对象程序设计
面向对象程序设计(英语:Object-orientedprogramming,缩写:OOP)是种具有对象概念的程序编程范型,同时也是一种程序开发的方法。
它可能包含数据、属性、代码与方法。对象则指的是类的实例。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性,对象里的程序可以访问及经常修改对象相关连的数据。
优点
- 良好的可重用性
- 易维护
- 良好的可扩展性
三原则
封装
继承
-
泛化
-
- 实现继承:使用基类的属性和方法,无需额外编码
可视继承:子类使用基类的外观和实现代码
组合
-
- 接口继承:仅使用属性和方法的名称、但是子类必须提供实现
- 纯虚类
多态
-
覆盖:子类重新定义父类的函数(动态)
-
- 虚函数
接口
重载:允许存在多个同名函数,而这些函数的参数表不同(静态)
特征
- 里氏原则:子类型必须能够替换它们的基类型
- 开闭原则:软件对扩展应该是开放的,对修改应该是关闭的
- 封装:封装是通过限制只有特定类的对象可以访问这一特定类的成员,而它们通常利用接口实现消息的传入传出。同时还可以将相关的常量定义、类型定义、函数声明等通过文件进行封装;也可以通过namespace进行封装
- 继承:在某种情况下,一个类会有“子类”,子类比原本的类(称为父类)要更加具体化。
- 多态:多态性是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。
友元
定义在类外部的普通函数或类,需要在类体内进行说明,为了与成员函数区别,需要在前面加关键字friend
友元函数或友元类可以访问类中的私有成员
提高程序运行效率,破坏了类的封装性和隐藏性
RTTI(Run-Time Type Identification)
通过运行时类型信息程序能够使用基类的指针或引用来检查这些指针或引用所指的对象的实际派生类型。
两个操作符
- typeid(头文件):返回指针或引用所指的实际类型
- dynamic_cast:将基类类型的指针或引用安全地转换为派生类型的指针或引用
STL
STL是标准模版库(StandardTemplate Library)的简写。
STL包含4个组件,分别为算法、容器、函数、迭代器。
STL的目的是提供对常用需求重新开发的一种代替方法,具有很高的性能并且免费。
标准模板库是可重用的,提高了开发效率。
算法
STL提供了一些常见的算法,如排序和搜索等。这些算法与数据结构的实现进行了分离。因此,用于也可对自定义的数据结构使用这些算法,只需让这些自定义的数据结构拥有算法所预期的迭代器。
容器
容器是包含其它对象的对象。标准模板库容器类包括两种类型,分别是顺序和关联
顺序容器可以提供对其成员的顺序访问和随机访问。
关联容器则通过优化关键值访问元素。
数据容器 | 描述 |
---|---|
序列容器 - 有序集 | |
vector | 动态数组,兼容C语言数组。vector可以如同数组一样的访问方式,例如使用下标(operator[])运算符,并记得自己的长度信息(size),您也可以使用对象的方式来访问vector(push_back、pop_back)。使用vector可以轻易地定义多维可调整型数组(std::vector |
迭代器
迭代器是泛化的指针,通过使用迭代器,开发者可以操作数据结构而无需关心其内部实现。根据迭代器的操作方式的不同,迭代器分为五种:
- input iterators
- output iterators
- forward iterators
- bidirectional iterators
- random access iterators
ACM必备
容器相关
vector不定长数组,图的邻接表常用vector+数组或vector套vector来表示
list 双向链表,
stack 栈
queue单向队列,用于BFS等
priority_queue优先队列,用于堆优化等
pair 键值对
set 集合,map 映射
multiset,multimap 允许重复的set和map
bitset 位集合
函数
min, max求最小值,最大值
swap交换两个元素
sort,stable_sort排序
lower_bound,upper_bound,binary_search,equal_range二分查找
next_permutation求下一个字典序,常先sort然后与do…while结合进行全排列遍历
random_shuffle打乱一段区间
常用类
valarray数值数组
complex复数类
常用函数
find,find_if区间内查找元素
count,count_if 区间内统计元素
search区间内查找子区间
min_element,max_element找区间的最小值, 最大值
fill 填充区间
unique去重,需要先sort,并且不是真正的去重
reverse反转区间
merge合并两个有序区间
swap_range交换两个区间
adjacent_find区间内查找相邻的相同的元素
mismatch找两个区间第一个不同的地方
equal比较两个区间是否相等
partition,stable_partition把区间一分为二
partial_sort局部排序
nth_element把第n大的元素放在其相应位置,左边都比它小,右边都比它大,但不保证有序
set_union,set_intersection,set_difference,set_symmetric_difference求有序集合的并,交,差,对称差
make_heap,push_heap,pop_heap,sort_heap对一段区间建立堆,插入堆,弹出堆,堆排序
accumulate求一段区间的累和或累乘等
adjacent_difference求一段区间各元素的相邻差
inner_product求两个区间对应元素乘积的和
partial_sum求一段区间各个位置的前缀和
C++11
auto自动类型推导
lambda匿名函数,用在函数里需要传入函数的地方
for-range范围for循环,结合auto使用
unordered_set,unordered_map利用hash表实现的set和map
iota生成一段递增的区间,可用于并查集初始化等