【侯捷面向对象高级开发】第二部分:面向对象 Object Oriented

目标学习class之间的关系

  • 继承 inheritance
  • 复合 composition
  • 委托 delegation

Object Oriented Programming, Object Oriented Designed

OOP, OOD

面向对象的编程

组合与继承

Inheritance(继承)

Composition(复合)

Delegation(委托)

1.1 Compositon(复合),表示has-a

一个类中,包含了另一个类,就叫复合。生命周期同步。

如下,queue类里面包含了Sequence类。

(1)queue has a deque(实心代表has-a复合)

Composition(复合),表示has-a 设计模式是:Adapter适配器 Adapter:queue has deque, 它所有的接口都可以用deque实现

template <class T> 
class queue
{ ... 
protected: 
     deque<T> c; //底层容器 queue has a deque public: // 以下完全利用c的操作函数完成 
    bool empty() const 
    { 
        return c.empty(); 
    } 
    size_type size() const 
    { 
        return c.size(); 
    } 
    reference front() 
    { 
        return c.front(); 
    } 
    reference back() 
    { 
        return c.back(); 
    } 
    void push(const value_type& x) 
    { 
        c.push_back(x); 
    } 
    void pop() 
    { 
        c.pop_front(); 
    } 
};

(2)从内存的角度分析Compositon

(3)Compositon(复合)关系下的构造和析构

构造由内而外(这样结构才稳定)

Container的构造函数首先调用Componet的default构造函数,然后才执行自己

Container::Container(...):Component(){...}; //先Component()后Container()

析构由外而内(从外部开始)

Container的析构函数首先执行自己,然后才调用Compositon的析构函数。

Container::~Container(...){...执行Container的析构操作 ~Component(); }

1.2 Delegation(委托). Compositon by reference

一个类,仍然包含另一个类,但是不是通过内存直接包含,而是用一个指针包含。 

生命周期不同步(String先创建,有需要时才创建stringRep)。

如下,String类委托了一个StringRep类。

委托可以对外接口一致,String接口永远不变,但是内部实现可以通过修改StringRep改变。

有a、b、c 3个变量在使用同一个字符串hello, 采用引用计数

如果a要改变hello,但不可以影响b、c,采用copy on write, 先复制一份然后修改

//file String.hpp class StringRep; 
class String
{ 
public: 
    String(); 
    String(const char* s); 
    String(const String& s); 
    String &operator=(const String& s); 
    ~String(); ... 
private: 
    StringRep* rep; //Composition by reference pimpl 
}; 
//file String.cpp 
#include <String.hpp> 
namespace 
{ 
    class StringRep
    { 
        friend class String; 
        StringRep(const char* s); 
        ~StringRep(); 
        int count; 
        char* rep; 
    }; 
} 
String::String() { ... } 
... 
Pimpl(Pointer to implementation) 是一种减少代码依赖和编译时间的C++编程技巧,其基本思想是将一个外部可见类(visible class)的实现细节(一般是所有私有的非虚成员)放在一个单独的实现类(implementation class)中,而在可见类中通过一个私有指针来间接访问该实现类。

Pimpl(Pointer to implementation) 是一种减少代码依赖和编译时间的C++编程技巧,其基本思想是将一个外部可见类(visible class)的实现细节(一般是所有私有的非虚成员)放在一个单独的实现类(implementation class)中,而在可见类中通过一个私有指针来间接访问该实现类。

1.3 Inheritance(继承),表示is-a

(1)使用public继承,就是在传达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; };

(2)继承关系下的构造和析构

Base class的析构函数通常设置为virtual ,这样可以保证析构时由外向内。

构造由内而外

Derived的构造函数首先调用Base的default构造函数,然后执行自己。

Derived::Derived(...): Base(){ ... };

析构由外而内

Derived的析构函数首先执行自己,然后才调用Base的析构函数。

Derived::~Derived(...) {... ~Base() };

1.3 表示is-a关系,Inheritance(继承)with virtual functions(虚函数)

(1) 当我我们使用继承时,是要搭配虚函数来使用,才会产生强而有力的效果。

non-virtual函数:你不希望derived class 重新定义(override,覆写)它

virtual 函数:你希望derived class 重新定义(override覆写)它,且你对它已有默认定义。

pure virtual 函数:你希望derived class一定要重新定义(override覆写)它,但是没有默认定义。

虚函数重新定义才叫override,覆写

class Shape
{ 
public: 
    virtual void draw() const = 0; //pure virtual //子类必须重新定义 
    virtual void error(const std::string& msg); //impure virtual//子类可以重新定义 
    int objectID() const; //non-virtual //不希望子类重新定义 
}; 
//继承 
class Rectangle:public Shape {...}; 
class Ellipse:public Shape {...};

(2) Template Method(Inheritance with virtual)

#include <iostream> 
using namespace std; 
class CDocument 
{ 
public: 
    void OnFileOpen() 
    { //这是个算法,每个cout输出代表一个实际动作 
        cout<<"dialog..."<<endl; 
        cout<<"check file status..."<<endl; 
        cout<<"open file..."<<endl; 
        Serialize(); 
        cout<<"close file..."<<endl; cout<<"update all views..."<<endl; 
    } 
    virtial void Serialize(){ }; 
}; 
class CMyDoc : public CDocument 
{ 
    public: 
    virtual void Serialize() 
    { //只有应用程序本身才知道如何读取自己的文件(格式) 
        cout<<"CMyDoc::Serialize()"<<endl; 
    } 
}; 

int main() 
{ 
    CMyDoc myDoc; //假设对应[File/Open] 
    myDoc.OnFileOpen(); 
}

(3) Inheritance + Compositon关系下的构造和析构

(4) Delegation(委托) + Inheritance(继承)

文件只有一份,有多种呈现形式,Observer可以被继承

实例一:

class Subect 
{ 
    int m_value; //要被观察的数据 
    vector<Observer*> m_views; //委托 //观察者列表 
public: 
    void attach(Observer* obs) 
    { 
        m_views.push_back(obs); 
    } //修改值之后,要通知所有的Observer,让它们做出改变 
    void set_val(int value) 
    { 
        m_value = value; notify(); 
    } 
    void notify() 
    { 
        for(int i=0; i<m_views.size(); ++i) 
            m_views[i]->update(this,m_value); //调用Obeserver的方法,去更新Obeserver的显示。把自己指针传出去 
    } 
}; 
class Observer //作为基类被多个观察者或显示着继承 
{ 
public: 
    virtual void update(Subject* sub,int value) = 0; //纯虚函数,让子类的观察者真正去显示这个值 
};

class Observer1 : public Observer 
{ 
    int m_div; 
    public: 
    Observer1(Subject* model, int div) 
    { 
        model-attach(this); 
        m_div = div; 
    } /*virtual*/ void update(int v) { ... } 
}; 
class Observer2 : public Observer 
{ 
    int m_mod; public: 
    Observer2(Subject* model,int mod) 
    { 
        model->attach(this); 
        m_mod = mod; 
    } /*virtual*/
void update(int v) 
{ ... } 
}; 
int main() 
{ 
    Subject subj; 
    Observer1 o1(&subj,4); 
    Observer2 o2(&subj,3); 
    Observer3 o3(&subj,3); 
    subj.set_val(14); 
}

实例二:

class Component { 
    int value; 
    public: Component(int val) 
    { value = val; } 
    virtual void add(Component*) { } 
}; 
class Primitive : public Component 
{ 
    public: Primitive(int val) : Component(val) {} 
}; 
classs Composite : public Component 
{ 
    vector<Component*> c; 
 public: 
    Composite(int val) : Component(val) { } 
    void add(Component* elem) 
    c.push_back(elem); 
};

实例三:父类想创建未来才定义的子类。

我需要一个树状继承体系,我需要创建未来才能出现的子类,设计一个框架,未来客户买去才会创建。

我不知道未来的子类是什么,那我怎么创建。

让派生的子类都创建一个子类,让父类框架可以看到,我就可以Copy。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值