C++学习笔记2-类之间的关系

这一部分主要介绍C++面向对象,多个类之间的关系。另外介绍了虚函数及其实现机制和一些设计模式。

  • Inheritance 继承 is-a
  • Composition 复合 has-a
  • Delegation 委托

Composition 复合 has-a

class queue
{
    ...
protected:
    deque<T> c;
public:
    void pop() {c.pop_front();}

};

类queue是一个队列,deque是双向队列,比queue功能强大。这里设计queue包含deque,所以是has-a,这种设计模式又叫做adapter.

构造函数

构造由内而外:Container::Container(): Component(){…}; //默认调用默认构造函数

析构由外而内:Container::Container(){… ~Component()};

Delegation-composion by reference

String 
{
    StringRep* rep;
}

一个类有另一个类的指针。复合的生命是同步的,有了A就有B,但是委托的生命不是同步的,当需要调用b的时候b才会生成。这种写法叫做pimpl(pointer to implementation或者handle/body)。这种方法的好处是,String类的具体实现可以不同,但是接口都一样,所以客户端不变,实现方法可以变化。

上面这个例子的图示如上,每生成一个String类,都会增加一个reference counting,共享空间。如果a要改变数据,会单独拷贝一份数据给a。

Inheritance is-a

struct _List_node_base
{
    _List_node_base* _M_next;
    _List_node_base* _M_prev;
};

template<typename _Tp>
struct _List_node
    :public _List_node_base
{
    _Tp _M_data;
}

构造由内而外,析构由外而内

**base class 的dtor必须是virtual,否则会出现undefined behavior **

inheritance with virtual function

  1. non-virtual函数 :不希望derived class重新定义它
  2. virtual函数:希望derived class 重新定义它(override),并且对它已经有默认定义。
  3. pure virtual:希望derived class一定要重写它,并且没有默认定义。

举例:
class Shape{

public:
virtual void draw() const=0; 	//pure virtual
virtual void error(const std::string& msg);	//impure virtual
int objectID() const;	//non-virtual

}

应用:Template Method(先搭出来一套框架,具体实现延迟到应用再实现)

如上图,对于打开文件这个动作,可以先设计一套框架,但是对于serialize这个函数,父类无法实现,于是声明为虚函数。当调用的时候,子类的指针调用父类的函数,但是具体实现是用的子类复写的方法。过程见灰色的线。

Inheritance+Composition

Delegation+Inheritance

Observer模式

composite模式

prototype模式

对象模型

vptr和vtbl

静态绑定:call XXX
动态绑定满足3个条件:

  1. 通过指针
  2. 向上转型
  3. 调用虚函数

由于指针不确定,所以称为动态绑定。

看图中3个类的继承关系A<-B<-C, A中有两个虚函数,两个非虚函数。 B继承了A,所以也有两个虚函数,但是对其中一个虚函数进行了重写。同样C也是。所以这里一共有8个函数。如图所示。这里对虚函数的继承是指的对调用权的继承,具体的机制是,每个类都有一个虚指针,指向一个虚表,虚表中存放所有虚函数的地址。具体的调用形式见图上下方。

this指针

myDoc.OnFileOpen()在调用的时候会传一个参数this,这里this指的就是myDoc这个子类的对象。然后调用OnFileOpen()的时候会把这个指针传到函数中,这个函数中所有的调用都变成了this->XXX(),当调用Serialize()的时候,转换成(*(this-vptr)[n])(this)这种形式,动态绑定子类的Serialize()函数。