Essential C++

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); 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值