1.p140
设计继承层次时需要小心,否则可能陷入一些隐蔽的错误。
比如我们设计一个Rectangular的父类,然后把Square作为派生类继承Rectangular类
Rectangular基类有三个数据成员分别是Point类型的变量bp,double height,double width,这三个成员的访问级别都是protected。我们为Rectangular类定义了默认构造函数,复制构造函数,以及setHeight函数等等,这时候Square类应该如何设计?
如果我们Square类直接继承Rectangular的数据成员。并且派生类继承了基类的默认构造函数。这时候会破坏consistency。因为此时的Square并不是Rectangualar的特殊情况。
另一种方式是定义Square类的一个Rectangular类型的数据成员并且重写默认构造函数和其他构造函数
2.一些原则
1)avoid deep inheritance hierarchies
2)try to creat base classes with as few member data as possible
注意声明非虚函数是为了让派生类继承函数接口和一份强制性实现。
3.一个例子 Two-factor payoff functions and classes
这个类的设计与之前的single factor是类似的,比较好的两种做法是
定义一个仅包含一个函数成员而无数据成员的抽象类,并把该函数成员声明为纯虚函数。然后派生类继承该函数的接口并分别定义自己的payoff版本。
如果每个Payoff函数所需要的参数都相同,那么我们可以不定义抽象类和利用继承关系而是直接定义一个具体类,该类的数据成员包含一个函数指针,再分别定义一系列Payoff的函数放在namespace中。更多的想法,可以参考胡扯OO和泛型编程
上面的抽象类可以写为:
class MultiAssetPayoffStrategy{
//interface specification
public:
virtual double payoff(double S1,double S2) const=0;
};
4.回顾C++ Primer中Base和Bulk_Item的例子,当派生类定义了自己的复制构造函数和赋值操作符时,派生类要显示调用基类的复制构造函数初始化对象的基类部分;要使用基类的该操作符来初始化对象的基类部分。
Bulk_Item Bulk_Item::operator=(const Bulk_Item &rhs){
Base::operator=(rhs);
};
Bulk_Item::Bulk_Item(const Bulk_Item &rhs){
Base(rhs);
};
5.Casting between types
casting is the process of converting an object pointer of one class to an object pointer of another class.
必须区分static casting(作用于非多态类),以及dynamic casting(作用于多态类,也就是说其成员函数至少有一个是虚函数),回顾动态绑定的两个条件。以及派生类的实例也是基类的实例这一基本原则。
dynamic_cast
D1 d1A;
Base *base2=&d1A;
D1 *d1Cast=dynamic(base2);
6.try,throw and catch: Ingredients of the C++ exception mechanism ,p141起
也可以看C++ Primer p186起
异常就是运行时的不正常,例如运行时耗尽了内存或遇到意外的非法输入。异常存在于程序的正常功能之外,并要求程序立刻处理。
异常检测提供了程序中错误检测与错误处理部分之间的通信。
C++的异常处理包括:
1)throw表达式,错误检测部分使用这种表达式说明遇到了不可处理的错误。例如,
if(!item1.same_isbn(item2)){
throw runtime_error("Data must refer to same ISBN");
}
比如我们设计矩阵乘法时,可以使用throw避免维数不符合条件的矩阵相乘
2)try block,错误处理部分用它来处理异常。
try块后面是一个或多个catch子句。每个catch子句包括三个部分:关键词catch,圆括号内单个类型或者单个对象的声明——称为异常说明符,以及花括号括起来的语句块。如果try块中的代码产生了异常,而且该异常类型与catch子句匹配,则执行这个catch子句的语句处理这个异常。否则,异常将由外围try块处理或者终止程序。
还可以使用预处理器进行调试,assert
assert(p!=NULL);
STL的异常类exception classes
7.Chapter10 p153 Templates
C++ was the first mainstream object-oriented language to support the generic programming.
模板是泛型编程的基础。在利用泛型编程时,we create classes that do not use a concrete underlying data type for their representation but rather use an unspecified data type that will later be replaced by concrete type.
比如我们要建立一个Lattic类模板
template
class Lattice
{
//
};
Lattice Mybinomial();
Lattice myCallableBond();
8.自定义Range类模板
template
class Range
{
private:
Type lo;
Type hi;
Range();
public:
Range(const Type &low,const Type &high);
Range(const Range &rhs); //copy constructor,仅有一个实参是对该类型对象的引用,要记住类型是Range
virtual ~Range();
};
template
Range::Range(const Type& l,const Type &h)
{
if(l
一定要注意
1).类名是Range
2).template关键词必须用于每一个成员函数。
并且除了code file要包含相应模板的header file外,source file必须include code file,i.e. cpp file而不是header file,这是类模板和函数模板的头文件包含规则与普通类和函数的区别。
9.chapter11 Generic Data Structures and Standard Template Library(STL)
主要的几类数据结构:
lists and vectors (linear sequence data)
maps and multimaps (key-value pairs)
sets and multisets
specially adapted containers such as stacks and queues
上述的容器十分有用,比如我们可以把他们作为类的成员,存放不同类型的数据,利用STL中的容器存放自定义的数据类型
复杂性分析与渐进符号,这部分可看原本的Weblog。下面就是对几种数据类型的介绍
标准库定义了三种顺序容器类型:vector、list 和 deque(是双端队列“double-ended queue”的简写)。它们的差别在于访问元素的方式(顺序迭代器与随机迭代器),以及添加或删除元素相关操作的运行代价。
标准库还提供了三种容器适配器(adaptors)。 实际上,适配器是根据原始的容器类型所提供的操作,通过定义新的操作接口,来适应基础的容器类型。顺序容器适配器包括 stack、queue 和 priority_queue 类型
适配器就是指使得一种抽象数据类型所支持的操作用另一种抽象数据类型的方式加以实现。
1)Lists
lists是sequential container即顺序容器的一种,包括以下几种具体类型
Singly linked list
Doubly linked list (supported in STL)
Circular list
Skip list
singly linked list的每一个节点包含该节点的值和指向下一个节点的指针。回顾我们使用二叉树统计输入的单词的词频时,每一个二叉树的节点包含两个三个指针成员,其中两个是指向左子树和右子树的指针。
doubly linked list的每一个节点包含两个指针,分别指向successor and to a predecessor,对于double linked list,以下操作只需要常数时间O(1)
Insert an element at the beginning/end of the list
Delete the first/last element
Merge two lists
Insert/delete an element at any position in the list
The following operations have O(n) complexity: 下面操作具有O(n)复杂度
Reverse the order of elements in the list Delete identical consecutive elements except the first one
也就是说在任意位置插入或删除元素对于doubly linked list都只要常数时间,这就是C++ Primer上说的List支持快速插入和删除,List中的数据不是连续存储的。
2)Stacks and Queues后进先出栈和先进先出队列
我们可以把栈这一数据结构理解为桌上堆叠的盘子,所以是后进先出。对于栈,我们常常使用以下的几种操作
清楚所有元素,判断栈是否为空,在栈顶添加元素push,去除栈顶元素pop,即 Put an element on the top of the stack (Push) Take the topmost element from the stack (Pop)
标准库支持三种类型的queue,包括
Double-ended queue (called deque)
FIFO (First In, First Out) queue
Priority queue
注意deque和List类似,在头尾插入和删除元素都只要常数时间,但是其他地方则要O(n),因为这时需要移动元素。
由于队列是先进先出的,因此队列的接口的限制比deque更强,It can be modelled by adapting the interface of a deque. 即queue可以是容器deque的适配器
In STL, a priority queue always gives the element with the highest priority. We specify the priority criteria when creating the queue. This could be the greatest or smallest number in the queue, for example. In general, however we characterise the criterion by using a suitable function object for comparison.We have included some examples on the CD to show how this technique works.
10.We define the class P to consist of those decision problems that can be solved on a deterministic sequential machine in the amount of time that is a polynomial function of the size of the input. The classNP (non-deterministic polynomial time) consists of all those decision problems whose positive solutions can be verified in polynomial time given the right information, or equivalently, whose solution can be found in polynomial time on a non-deterministic machine. In complexity theory, the NP-complete problems are the most difficult to solve inNP in the sense that they are the ones most likely not to be in P. An example of an NP-complete problemis the subset sum problem: given a finite set of integers, determine whether any non-empty subset of them sums to zero.
复杂度类P包含所有那些可以由一个确定型图灵机在多项式表达的时间内解决的问题;类NP由所有其肯定解可以在给定正确信息的多项式时间内验证的决定问题组成,或者等效的说,那些解可以在非确定图灵机上在多项式时间内找出的问题的集合。
要解决P = NP问题,NP完全的概念非常有用。不严格的讲,NP完全问题是NP类中“最难”的问题,也就是说它们是最可能不属于P类的。这是因为任何NP中的问题可以在多项式时间内变换成为任何特定NP完全问题的一个特例。例如,旅行商问题的判定问题版本是NP完全的。所以NP中的任何问题的任何特例可以在多项式时间内机械地转换成旅行商问题的一个特例。所以若旅行商问题被证明为在P内,则P = NP!旅行商问题是很多这样的NP完全的问题之一。若任何一个NP完全的问题在P内,则可以推出P = NP。不幸的是,很多重要的问题被证明为NP完全,但没有一个有已知快速的算法。
11.算法的类别
一些重要的算法:
B1
find: locate an element in a container
count: number of elements whose value equals a target value
search: search for a subsequence within a sequence
B2
copy: make a copy of a container
swap: swap the contents of two sequences
transform: modify a sequence and copy it into another container
replace: replace a value by another value
unique: delete identical consecutive elements
reverse: ‘first will be last and last will be first’ remove: delete an element having a certain value
算法是通过迭代器作用于不同类型的容器的,迭代器是算法和数据结构之间的媒介。
STL中的find算法
template
inline _InputIterator
__find(_InputIterator __first, _InputIterator __last,
const _Tp& __val, input_iterator_tag)
{
while (__first != __last && !(*__first == __val))
++__first;
return __first;
}
12.迭代器
迭代器可以视为算法和数据结构之间的媒介,回顾STL并没有为顺序容器添加很多操作,即成员函数,而很多操作是通过定义一组算法实现的,这些算法通过迭代器来实现对容器的操作,而与具体的容器类型无关。
迭代器的类型
Forward and backward iterators
Sequential and random access iterators
Iterators that read from, and iterators that write to the data structure
比如vector容器的迭代器就支持快速随机访问,而List容器的迭代器则不支持。还有只读不写迭代器const_iterator
一些C++ Primer书上内容的整理可以参见链接
13.一个数据结构和算法的简单例子
vector,在尾部插入或删除元素需要常数时间,其他位置需要O(n)时间,长度可变且内存管理是自动的。支持快速随机访问。
书写vector容器的打印操作,使用函数模板和只读不写迭代器
template
void print(const vector &myVec,)
{
for(vector::const_iterator iter=myVec.begin();iter!=myVec.end();++iter
cout<<*iter<<" ";
cout<
14.对之前的一些问题的回顾:
计算一个数乘以另一个数30*x,需要灵活使用位运算,我们已经知道右移一位>>1,则原来的数变为1/2
更多内容可以参考链接,以及位运算判断奇偶等等 & 01
每个类都定义了一个接口和实现。接口由使用该类的代码需要执行的操作构成。实现一般包括该类所需要的数据。回顾函数的接口和实现,函数的接口可以理解为函数原型。纯虚函数是为了让派生类获得可供继承的接口。回顾纯虚函数,抽象类。
const指针数组的使用,
char *const color[6] = { "BGC", "BCG", "CBG", "CGB", "GBC", "GCB" }; //const指针数组,回顾const指针和指向const对象的指针
动态数组的使用见链接第16条
map map1;
map1["A"]=1.0;
pair tmp("B",2.1);
//也可以用模板函数make_pair,pair tmp=make_pair("B",2,1);
map1.insert(tmp);
//还可以使用anonymous object
map1.insert(pair("B",2.1));
void print(const map &myMap)
{
cout << "Number of elements in map: " << myMap.size() << endl;
// Iterating in the map
map::const iterator i = myMap.begin();
while (i != myMap.end())
{
// NOTE THIS SYNTAX: IMPORTANT
cout << (*i).first << ", " << ((*i).second) << endl;
i++;
}
cout << endl;
}
mymap.erase("B");
mymap.erase(mymap.begin());
mymap.erase(mymap.begin(),mymap.end());
maymap.clear()
typedef map SparseRow; //该类型表示矩阵的每一行
template //模板非类型形参来表示矩阵的维数,行数
struct SparseMatrix
{
map data;
} ;
const int N = 5;
SparseRow current;
current.insert(pair (0, -2.0)); //使用anonymous object进行初始化
current.insert(pair (1, 1.0));
SparseMatrix sparseMat;
sparseMat.data[0] = current;
int currentIndex = 0;
for (int row = 1; row < N-1; row++)
{ // Insert 3 elements
current.clear();
current.insert(pair (currentIndex, 1.0));
current.insert(pair (currentIndex+1, -2.0));
current.insert(pair (currentIndex+2, 1.0));
sparseMat.data[row] = current;
currentIndex++;
} //这是对sparsematrix的每一行进行赋值,每一行都是SparseRow类型。
current.clear();
current.insert(pair (N-2, 1.0));
current.insert(pair (N-1, -2.0));
sparseMat.data[N-1] = current;
print(sparseMat);
上面这部分内容非常重要,任何使用map来构造的特殊矩阵类型,进行该类型对象的初始化时,我们都可以先定义一个相应的Row类型,再定义一个以Row类型为基础的矩阵类型,并且利用Row类型对象的赋值和erase,clear操作实现初始化。而且上卖弄的内容也揭示了如何使用模板非类型形参来表征矩阵的维数(行数)
使用模板函数来实现对上面定义的SparseMatrix类型对象的打印,非常重要
template
void print(SparseMatrix& sm)
{
SparseRow sr;
SparseRow::const iterator it;
for (int row = 0; row < N; row++)
{
SparseRow sr = sm.data[row];
// Now iterate over row
for (it = sm.data[row].begin(); it != sm.data[row].end();it++)
{
cout << (*it).second << ", ";
}
cout << endl;
}
}
16.set
STL中的set
比如
set mySet;
mySet.insert("r");
mySet.insert("d");
set vset(mySet); //copy constructor
我们可以利用set写一些模板函数,比如两个set的并集
template
void UnionSet(const set &s1,const set &s2,set &myunion)
{
set::iterator i=myunion.begin();
insert_iterator> insertier(myunion,i);
set_union(s1.begin(),s1.end(),s2.begin(),s2.end(),insertiter);
}
以及书写判断是否是子集或者超集的代码,见p211
重写stl的set,使其更加友好
template class SetThing{};
tempalte
class Set: public SetThing //回顾SetThing是类的名称,而具体的类型是SetThing,类的派生列表和类的成员函数的书写要注意
{
private:
set s;
public:
typedef set::iterator iterator;
typedef set::const_iterator const_iterator;
public:
Set();
Set(const Set & stlSet); //create a set from STL set
Set(const Set & s2); //copy constructor
//construct a set from V that has STL-compatible iterators
Set(const list & con);
Set operator=(const Set &s2);
virtual ~Set();
//Standard operations
friend Set Intersection(const Set &s1,const Set &s2)
friend Set Union(const Set &s1,const Set &s2)
Set operator + (const Set &s2);
friend Set Difference(const Set &s1,const Set &s2)
Set operator - (const Set &s2);
Set SymmetricDifference(const Set &s1,const Set &s2);
Set operator % (const Set &s2);
templateSet> operator * (const Set & s2);
iterator Begin();
const_iterator Begin() const;
iterator End();
const_iterator End() const;
//operations on a single set
long Size() const;
void Insert(const V& v);
void Insert(const set& v);
void Remove(const V &v);
void Clear();
...
//Relations between sets
bool Subset(const Set &s2) const;
bool Superset(const Set &s2) const;
bool Intersects(const Set &s2) const;
}
17.下面就用之前写的Set类型和Map来定义AssocArray和AssocMatrix类型,
template
class AssocArray
{
private:
map str;
Set keys;
public:
//
};
对于AssocMatrix类型,有三个模板类型形参,即row data type,column data type,values data type
template
class AssocMatrix
{};
回顾用map类型来实现matrix algebra。
18.Data structures for financial engineering application ch13
在金融工程中有几种常用的数据结构,包括
1)Lattice and other related structures(for example,implied trees)
2)Properties,property sets and flexible "member data" for financial instruments
3)vectors and matrix
这些数据结构将应用于求解线性方程,数据插值,求解收益率曲线
我们在定义类的时候经常将类的数据成员私有化,这样只有类的成员可以访问这些数据成员,而类的使用者则不能。也就是说这些hard-coded member data remain a compile time phenomenon, it is not possible to query an object for its member data at run-time. 我们也不能在运行时添加member data.
对此,我们可以使用Property Pattern,使得我们能够在运行的时候让对象访问其状态the ability of objects to query their own state at run time.
回顾struct可以利用初值表进行初始化,表达类似于数组。
我们在class的公共访问区域定义一个property,这样类的用户就可以直接获得这些Property.
书P222给出了一个Property Pattern的例子,Deep copy以及Visitor Pattern
19.Property Sets
现实问题:对于像期权这样的金融资产,包含一系列的Property,这些property都可以看成key-value pair,所以我们定义一种结构描述a list of key-value pairs,称之为simple property set.,该数据类型包含三个成员,Set
template:public PropertyThing
{
private:
N nam;
map s1;
Set keys;
public:
};
20.Lattice
三叉树和二叉树是常见的数据结构,我们要写recombining trees。lattice node是泛型的,我们可以在节点存放不同类型的对象。这部分内容见书。
21. 设计模式(重点 )
首先,我们