1. 局部静态对象 -- 堆对象?
2. 默认参数 --1.只能定义一次,(头文件或cpp文件)。2. 默认值的决议(resolve)从最右侧开始。
意味着void fun(int a = 0, int b, int c =2)是不正确的
3. Overload vs Template
Overload -- 多份实现
Template - 主体不变,数据类型改变
template的定义
template<typename eleType> fun(const vector<eleType> &vec){
for(int i=0;i<vec.size();++i)
eleType t = vec[i];
...
}
4. 函数指针
普通函数的定义
e.g
const vector<int>* fibon_seq(int size)
函数指针的定义
e.g
const vector<int>* (*seq_ptr)(int)
函数指针的举例
bool seq_elem(int pos,int &elem,const vector<int>* (*seq_ptr)(int)){
const vector<int> *pseq = seq_ptr(pos); //调用函数指针方式和普通函数一致
if(!pseq) //做检查
....
}
函数指针的初值可以为0
const vector<int>* (*seq_ptr)(int) = 0;
也可以为某个函数的地址
const vector<int>* (*seq_ptr)(int) = fibon_seq;
5. inline
inline必须定义在头文件中
6. include
include <*.h> - <>表示标准库中的头文件
include “*.h“ — ”“表示自定义文件
7. 数组
数组作为函数参数传入,传第一个元素的地址
8. vector vs list vs deque
vector - 连续内存存放sequence data。(数组)随机读取效率高
list - 双向链表存放sequence data。 插入删除效率高
deque -类似vector,前、末端插入、删除效率高,用来实现queue.
直接用[]可以访问序列化容器
9. 引用,指针
引用:永远指向第一次赋值时所指向的对象。
引用,指针作为函数参数来传递对象的时候,效果是一样的:
1.能直接对传人的对象进行修改。
2.并不对传入的对象进行复制。引用复制的是对象的地址,指针复制的是指针本身。
引用比指针优胜的地方:
引用可以避免空指针(*pt)错误。
当提领指针时,先判断改指针是否为0。引用无需这样判断。
if(pt != 0 && *pt == ...)
避免出错倾向,(外部调用时会惯性选择声明对象而非指针,减少内存泄漏的出错机会)
9.1 函数参数为引用的定义
public void fun(A &a){
A b(3);
a = b;
//或者这样实现
//A *c = new A(3);
//a = *c;
//delete a;
}
使用
A a(5);
fun(a);//执行完a=3
9.2 函数参数为指针
public void fun(A *a){
A b(3);
*a = b;//提领(dereference)
}
使用
A *pa = new A(5);
fun(pa);//执行完pa内容为3
//...使用pa
delete pa;
java的函数参数传递和 c++默认的函数参数传递都是传值。c++也允许传引用。
对引用对象进行的任何操作,都相当于对被传入的对象进行操作。包括赋值一个新的对象。
而在java中函数调用中是不可以的。如
void javafun(A a){
a = new A();
}
这样在java的函数调用完毕后a还是保持被调入时候的值。
但在c++中
void cplusfun(A &a){
A b;
a = b;
}
a在函数调用完毕后内容已改变。
10. 栈对象 vs 堆对象
栈对象(stack)- 如函数内定义的对象,临时被放置栈内,函数执行完毕,栈内的内容被弃置。
堆对象(heap)- 如动态分配内存的对象,由程序员自行管理。
11. Function Object
一个重载了function call:()的class对象,用于定义算子。它的作用和函数指针相似,但比函数指针好的地方在于效率,
令call运算符为inline。且能保持状态(类对象进行保存)
bind2nd,bind1nd也是function object,把二元Function object转成一元的,另一个参数则由bing*nd的构造函数参数指定。
12. 指针的指针,指针的引用
对指针内容的改变只需要传递指针。
对指针本身的改变,则需要传递指针的指针或指针的引用。
第四章 基于对象的编程风格
1.前置声明
前置声明(forward declaration) -- 得以进行类指针的定义或以此class为数据型别。编译前可见
作用类似include,如果嵌套include的话,则另一个类用前置声明。
e.g class Stack;
2.inline
直接在头文件定义或者在cpp文件中函数定义时指定关键字inline.
3.constructors
default constructors 可能为每个参数提供默认值。
e.g
Class Trigangular{
Triangular(int len = 1, int bp =1) //也是default constructor。
}
Trigangular t = 8; //调用的是只有一个参数的构造函数而非赋值操作符(assignment operator)
4. 成员初值表(Member Initialization List)
Member Initialization List紧跟在构造函数参数表冒号后面,用逗号分隔,用于将参数传给成员变量。
e.g Class Trigangular(const Trigangular &rhs):_length(rhs._length),_next(rhs._next)
{
}
成员初值表优于赋值(当member object时) 原理?
5.复制构造函数(copy constructor)和复制赋值操作符(copy assignment operator)改变
默认的成员逐一初始化行为(Memberwise Initialization)
e.g Trigangular t1(8);
Trigangular t2 = t1;
默认的t1的各个成员变量会赋值到t2的各个成员变量。
如果类中包含指针的成员变量,默认初始化会使两个对象的指针都指向相同的地址空间,t1析构时
会把指针指向的内存释放掉,而t2的指针仍指向该块内存。错误!
应提供copy constructor
Matrix::Matrix(const Matrix &rhs):_row(rhs._row),_col(rhs._rol)
{
int num = _row * _col;
_pmat = new double(num);
for(int i=0;i<num;i++)
{
_pmat[i]=rhs._pmat[i];
}
}
同时,提供copy assignment operator
Matrix& Matrix::operator=(const Matrix &rhs)
{
if(this != &rhs)
{
_row = rhs._row;_col = rhs._col;
int num = _row * _col;
delete[] _pmat;
_pmat = new double(num);
for(int i=0;i<num;i++)
{
_pmat[i]=rhs._pmat[i];
}
}
return *this;
}
copy assignment operator实现和copy constructor相似,有两点注意:
1.要判断赋值对象是否就是被赋值对象本身。
2.开始复制前要把原有的动态分配的内存释放掉。
6.const
编译器保证
1.const member function的实现不能改变class object。
2.const对象不能调用自身的非const member function.
member function可根据const与否重载。
e.g
class A{
const Bigclass val() const{return _val;}//1
//第一个const表示返回const的Bigclass对象,第二个const表示此方法不能改变class object
Bigclass val(){return _val;}//2
}
void example(const A &a,A b)
{
a.val();//invoke 1
b.val();//invoke 2
}
7.mutable(可变)
如果既希望把方法声明为const,在方法里会更改类对象,(从某种意义上讲,这种改变不会改变
class object状态,不算破坏对象的常数性,可把该变量声明为mutable.
class A{
public:
void next() const {_next = _beg_pos -1;} //ok
private:
mutable int _next;
int _beg_pos;
}
8.静态成员函数
声明:
class A{
static bool is_elem(int elem);
}
定义
bool A::is_elem(int elem){...}//不需加static
使用
boolean is_elem = A::is_elem(ival);
9.运算符重载
9.1 规则:
1.不引入新的运算符
2.四个运算符不予重载
.
.*
::
?
3.操作数不能改变
4.优先级不能改变
5.参数中必须有一个参数是class型别 ??
9.2 定义
member function:
int T_iterator::operator*() const
{
...
}
non-member function:
int operator*(const T_iterator &rhs) {....}
non-member function的操作运算符比member function的多一个参数,(member运算符的this),代表左侧操作数。
9.3 前置和后置
前置定义(++t)
T_iterator& T_iterator::operator++(){
++_index;
return *this;
}
后置定义(t++)
T_iterator T_iterator::operator++(int){
T_iterator tem = *this;
++_index;
return tem;
}
因为重载规定必须参数表不一样,所以C++要求后置版有一个int参数与前置区分。
编译器会自动为后置函数产生一个int引数(0).
9.4 function object 重载 ()
概念:function object 是提供function call实现的类。
声明和定义
class Less{
Less(int val):_val(val){};
boolean operator()(int value) const {return value < _val;};
}
使用
int count_less_than(const vector<int> &vec,int comp){
Less lt(comp);
int count = 0;
for(int i=0;i<vec.size();i++){
if( lt( vec[i] ) )
count++;
}
return count;
}
10.指向类成员函数的指针
10.1 定义
e.g void (ClassA::*pm)(int)=0;
或者
typedef void (ClassA::*PtrType)(int);
PtrType pm=0;
10.2 赋值
PtrType pm = &ClassA::functionA;
10.3 使用
ClassA a;
PtrType pm = &ClassA::functionA;
(a.*pm)(pos); //等同于a.functionA(pos);