[Boolan] C++第三周 类的关系。 复合,委托,继承

1. Composition复合

has a的关系,表示一个类是另一个类的成员变量,一个类包含另一个类
class A;
class B 
{
public:
    B(){}
    ~B(){}
private:
    A a;
    int b;
};

这里写图片描述

构造与析构

构造-由内而外:B的构造函数会首先调用A的默认构造函数(编译器自己调用,如果需要传递参数,需要在初始化列表显示调用),然后在调用自己的构造函数
    B::B(...):A(){...}

析构-由外而内:B的析构函数首先执行自己的,然后才调用A的析构函数
    B::~B(...){... ~A()}

Adapter作用

新需求所要求的所有功能在一个已有的C类中已经全部实现,但是C中功能繁多,此时可以设计一个类D对C的功能进行一次封装,仅暴露需要的结构结构,此时就非常适合Composition关系
class C;
class D
{
public:
    void func() { c.func(); }
private:
    C c;
};

2. Delegation委托

has a point
类的成员变量是另一个类的指针,
class A;

class B 
{
public:
    B(){}
    ~B(){}
private:
    A *a;
    int b;
};

这里写图片描述

这种方法有个名词pImpl(Pointer to IMPLementation),简单理解就是接口与实现分离

参考链接:
1. 明智地使用Pimpl
2. 编译防火墙——C++的Pimpl惯用法解析

典型用例

C++11中的string就是用了这种方法,方法和实际实现分离,这样就可以在两个字符串相同的时候,就使用同一块内存,当其中一个发生改变时就重新分配一块内存
可以通过下列代码进行验证,但请确保是在C++11版本(因为我只测试了这个版本)
#include <stdio.h>
#include <string>

using std::string;

int main(int argc, char *argv[])
{
    string s1("123456789");
    string s2(s1);
    string s3("123456789");

    printf("s1=%p, s2=%p, s3=%p\n", s1.c_str() , s2.c_str(), s3.c_str());

    s1 += "00";
    printf("s1=%p, s2=%p, s3=%p\n", s1.c_str() , s2.c_str(), s3.c_str());

    return 0;
}
----------------------
s1=00FC2AAC, s2=00FC2AAC, s3=00FC2ACC
s1=00FC3AF4, s2=00FC2AAC, s3=00FC2ACC

3. Inheritance继承

继承 is a,C++分为三种方式public,protected, private.使用最广泛的是public
class A
{
public:
    A(){}
    virtual ~A(){}
}
class B : public A
{
};

这里写图片描述

构造与析构

构造-由内而外:B的构造函数首先调用A的默认构造函数,然后在执行自己
    B::B():A(){...};
析构-由外而内:B的析构函数首先执行自己,然后才调用A的析构函数
    B::~B(...){...~A()};

注意:基类的析构函数必须是virual的,否则会出现undefined behavior

4. 应用

观察者模式

委托+复合
  1. 类图
    这里写图片描述
  2. 代码
#include <stdio.h>
#include <string>
#include <vector>
#include <iostream>

using std::string;
using std::vector;
using namespace std;

class Subject;
class Observer
{
public:
    virtual void update(Subject *sub, int value) = 0;
};

class Subject
{
public:
    void attach(Observer*obs)
    {
        m_views.push_back(obs);
    }
    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);
        }
    }

private:
    int m_value;
    vector<Observer*> m_views;
};

class View : public Observer
{
public:
    void update(Subject *sub, int value)
    {
        m_watchValue = value;
    }
    void paintView()
    {
        cout << m_watchValue<< endl;
    }
private:
    int m_watchValue;
};

int main(int argc, char *argv[])
{
    View v1;
    View v2;
    Subject s;
    s.attach(&v1);
    s.attach(&v2);
    s.set_val(100);
    v1.paintView();
    v2.paintView();
    cout << "-----------------------" << endl;
    s.set_val(200);

    v1.paintView();
    v2.paintView();

    return 0;
}
///----------------------
100
100
-----------------------
200
200

组合模式Composite(结构型)

  1. 参考链接:
    1. 设计模式(七)组合模式Composite(结构型)
    2. 组合模式(Composite Pattern )
    3. C++设计模式-Composite组合模式
  2. 典型应用场景
    windows的文件夹与文件系统,文件夹中又有文件
  3. 类图
    这里写图片描述
  4. 代码

class Component
{
public:
    Component(int val):m_value(val){}
    virtual void add(Component*){}
private:
    int m_value;
};

class Primitive:public Component
{
public:
    Primitive(int val):Component(val){}
};

class Composite:public Component
{
public:
    Composite(int val):Component(val){}
    void add(Component *elem) {
        c.push_back(elem);
    }
private:
    vector<Component*> c;
};

原型模式prototype

  1. 参考链接
    1. c++原型模式(Prototype)
    2. 原型模式(Prototype)C++实现
  2. 应用场景
    原型模式是通过已经存在的对象的接口快速方便的创建新的对象。
  3. 类图
    这里写图片描述
  4. 代码
#include <iostream>

using namespace std;

enum imageType
{
    LSAT, SPOT
};

class Image
{
public:
    virtual void draw() = 0;
    static Image* findAndClone(imageType);
    virtual ~Image() {}
protected:
    virtual imageType returnType() = 0;
    virtual Image *clone() = 0;
    static void addPrototype(Image *image)
    {
        _prototypes[_nextSlot++] = image;
    }

private:
    static Image* _prototypes[10];
    static int _nextSlot;
};

Image *Image::_prototypes[];
int Image::_nextSlot;

Image *Image::findAndClone(imageType type)
{
    for(int i = 0 ; i < _nextSlot; i++)
    {
        if(_prototypes[i]->returnType() == type)
        {
            return _prototypes[i]->clone();
        }
    }
    return NULL;
}



//////////////////////////////////////////////////////////////////////////
class LandSatImage:public Image
{
public:
    imageType returnType() {
        return LSAT;
    }
    void draw() {
        cout << "LandSatImage::draw " << _id <<endl;
    }
    Image *clone() {
        return new LandSatImage(1);
    }
protected:
    LandSatImage(int dummy) {
        _id = _count++;
    }

private:
    static LandSatImage _landSatImage;
    LandSatImage(){
        addPrototype(this);
    }
    int _id;
    static int _count;
};

LandSatImage LandSatImage::_landSatImage;
int LandSatImage::_count = 1;


//////////////////////////////////////////////////////////////////////////
class SpotImage:public Image
{
public:
    imageType returnType() {
        return SPOT;
    }
    void draw() {
        cout << "SpotImage::draw "<< _id <<endl;
    }
    Image *clone() {
        return new SpotImage(1);
    }
protected:
    SpotImage(int dummy) {
        _id = _count++;
    }
private:
    SpotImage() {
        addPrototype(this);
    }
    static SpotImage _spotImage;
    int _id;
    static int _count;
};
SpotImage SpotImage::_spotImage;
int SpotImage::_count = 1;



//////main
const int Num_IMAGES = 8;
imageType input[Num_IMAGES] = { LSAT, LSAT, LSAT, LSAT, SPOT, SPOT, LSAT};

int main()
{
    Image *images[Num_IMAGES];
    int i = 0;
    for(i = 0; i < Num_IMAGES; i++)
    {
        images[i] = Image::findAndClone(input[i]);
    }

    for(i = 0; i < Num_IMAGES; i++)
    {
        images[i]->draw();
    }

    for(i = 0; i < Num_IMAGES; i++)
    {
        delete images[i];
    }

    return 0;
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值