第一课 C++编程简介
基于对象(Object Based):学习对于单一对象设计。
面向对象(Object Oriented):学习类之间的关系(封装,继承,多态)
第二课 头文件与类的声明
类的经典分类,包括带有指针数据,和不带指针数据。
第三课 构造函数
构造函数:
- 可以有多个同名构造函数;
- 对于重载构造函数,需要避免冲突。
第四课 参数传递与返回值
构造函数放在private的情况,避免对象被外界创建。例如 Singleton模式
常量成員函數:对于不会改变对象数据的函数,一定要加上const关键字。
否则,在使用者声明const对象时,非const函数无法编译通过。
传值或传引用
- 函数传参时,尽可能传引用;
- 如果不希望函数改变引用参数值,需添加const关键字;
- 函数返回值,尽可能用引用(返回值不能是局部变量);
- 相同class的各个objects互为friends(友元);
- 构造函数一定要使用初始化(:)方式初始化数据。
第五课 操作符重载与临时对象
关于成员函数:
- 在C++里面,操作符实际上就是一种函数。
- 所有成员函数,都有一个隐藏的参数this指针,this指针指向调用者。
对于双目操作符(例如 +=),都是作用于左边的对象上,将右边对象加到左边对象上。
使用引用作为返回值的好处:
1. 传递者无需知道接收者是以reference形式接收。
2. 对于连续使用的情况,可以避免错误,例如 操作符+=, a += b += c。
非成员函数:无this对象指针。
对于将临时变量作为返回值的,不能返回引用形式。
对于输出操作符“<<”只能写成非成员函数(全局函数),原因:操作符“<<”在C++中,只能作用在左操作数上。
类的声明需要注意的事情:
1. 构造函数的初始化列表的使用;
2. 成员函数是否需要加const,避免某些副作用;
3. 参数的传递,尽量考虑传递引用;
4. 函数的返回值,尽量考虑返回引用;
5. 数据放在private里面。
个人小结:对于重载操作符,是否将其作为成员函数,每种操作符都有自己的位置,或者说C++都已经有定数。
例如,+=,适合作为成员函数;+ / -(加或减),适合作为全局函数;<<, 适合作为全局函数。
这定数是受什么影响?我认为有两方面:
- 所有成员函数,都有一个隐藏的参数this指针,this指针指向调用者。
- 函数功能和样式的影响,例如 +(加)可能需要支持多种数据类型的操作。
第六课 复习Complex类的实现过程
设计一个类的过程:
- 类需要什么数据,什么类型;
- 类对外需要提供什么函数;
- 构造函数怎样设计,参数是否要提供默认值,充分应用初始化列表,设置初值;
- 函数是否应该设计为成员函数,还是全局函数;
- 函数是否需要提供const属性;
第七课 三大函数:拷贝构造,拷贝复制,析构
对于带有指针数据的类,必须要写这三大函数。
拷贝构造:构造函数的参数是类自身的对象。
拷贝赋值:拷贝复制函数的参数是类自身的对象。
析构函数:析构函数在对象消亡时被调用。
拷贝赋值函数:检测不是自我赋值后,需要先释放自身的数据,再申请一个合适空间来存放赋值数据。
拷贝赋值函数一定要检测是否是自我赋值的情况。
第八课 堆,栈与内存管理
堆,栈与内存管理
stack(栈):是存在于某个作用域的一块内存空间。例如当你调用函数,函数本身即会形成一个stack用来放置它所接收的参数,以及返回地址。
heap(堆):是指由操作系统提供的一块global内存空间,程序可动态分配从中获得若干区块。
stack 的资源会在离开作用域时,会自动释放。heap 需要程序手动释放资源。
第九课 复习String类的实现过程
- 思考需要什么样的数据:放一个char* m_data即可。
- 需要开发给外界哪些函数:
构造函数:参数设计,是否设const,是否设初值。
拷贝构造:参数设计,是否设const。
拷贝赋值:参数设计,是否设const,返回值是否为引用形式。
析构函数:
其他的辅助函数:函数是否为const。
- 构造函数和析构函数
- 拷贝赋值函数
&符号:位于类型的后面,还是对象的前面,决定了符号的含义(引用类型,还是取对象地址)
第十课 类模板,函数模板,及其他
1. static关键字:
静态数据:所有对象只有一份数据
静态函数与非静态函数的区别在于:静态成员函数,没有this指针的隐藏参数。
所以,静态成员函数,只能存取静态数据。
调用静态成员函数的方式:
(1)通过object调用,例如 object.fun();
(2)通过class name调用,例如 class::fun()。
2.把构造函数放在private区
例如,单例设计模式:
3. class template 类模板
template<typename T>
class complex{
...
}
complex<double> c1(2.5,1.5);
complex<int> c2(2,6);
4. function template 函数模板
template <class T>
inline
const T& min(const T& a, const T& b)
{
return b < a ? b : a;
}
关键字typename 和 class是相同的意思。
编译器会对function template进行引数推导(argument deduction)
所以,调用function template时,可以不用指明类型。
5. namespace 命名空间
namespace std
{
...
}
标准库
使用方法:
1. using directive:例如 using namespace std;
2. using declaration: 例如 using std::cout;
3. 无需使用using,调用时指明。
第十一课 复合(composition),继承(inheritance),委托(delegation)
composition(复合),表示 has-a
类里面包含其他的类或者结构体的情况。
Adapter设计模式:基于现有的功能,封装成另外一种形式提供出去使用。
composition(复合)关系下的构造和析构
构造由内而外:Container的构造函数首先调用Component的default构造函数(编译器自动添加,如果不满意调用default构造函数,可以自己手动调用),然后才执行自己。
析构由外而内:Container的析构函数首先执行自己,然后才调用Component的析构函数(编译器自动添加)。
Delegation(委托),Composition by reference.
Handle/Body(point to implementation).
一个类的私有数据,使用一个指针指向另一个实现具体功能的类。
这样做的好处,可以将开放出去的功能接口与具体功能实现分隔开,实现编译防火墙。
Inheritance(继承),表示is-a
三种继承方式:public、protected、private。
构造由内而外:Derived的构造函数首先调用Base的default构造函数(编译器自动添加),然后才执行自己。
析构由外而内:Derived的析构函数首先执行自己,然后才调用Base的析构函数(编译器自动添加)。
如果一个class可能成为一个父类,其析构函数必须是virtual。
第十二课 虚函数与多态
Inheritance(继承) with virtual functions(虚函数)
函数的继承,继承的是函数的调用权。数据的继承,继承的是内存空间。
non-virtual函数:不希望derived class重新定义(override,重写)它。
virtual函数:希望derived class重新定义(override,重写)它,且已经有默认定义。
pure virtual函数:希望derived class一定要重新定义(override,重写)它,因为它没有默认定义。
通过子类对象调用父类函数,编译时会将子类对象(调用者)传给函数。
Template Method(模板方法设计模式)是虚函数的经典应用。
Inheritance+Composition关系下的构造和析构
Delegation(委托) + Inheritance(继承)的应用
Observer设计模式
第十三课 委托相关设计
Composite设计模式
Prototype设计模式