zoukankan      html  css  js  c++  java
  • C++ 组合与继承

    组合与继承

    Composition(复合),表示has-a
    复合关系简单来说,就是一个类中有另外一个类,A类中需要实现的东西,完全可以由B类中的方法来实现的话,就不需要在A类中去写,而直接去调用B类中的方法就行了。

    template <class T, class Sequence = deque<T>>
    class queue{
    ...
    protected:
    sequence c; //底层容器
    public:
    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();}
    };

    因为单向队列类queue中的一些操作完全可以由双端队列类deque中的方法去实现,所以可以在queue类中直接加入底层容器去调用deque中的方法,而不是自己实现,这就是复合。


    内存关系:

    template <class T>
    class queue{
    protected:
    deque<T> c;
    ...
    };

    template <class T>
    class deque{
    protected:
    Itr<T> start;
    Itr<T> finish;
    T** map;
    unsigned int map_size;
    }

    template <class T>
    struct Itr{
    T* cur;
    T* first;
    T* last;
    T** node;
    ....
    };

    算内存,由内而外,首先看结构体Itr,一个指针4字节,所以sizeof(Itr) = 4*4 =16
    然后在 class deque中,有两个Itr结构体 加一个指针变量一个整形变量,所以sizeof(deque) = 16 * 2 + 4 + 4 = 40;
    同理,所以sizeof(queue) = 40;

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

    构造由内而外
    Container 的构造函数首先调用 Component 的 default 构造函数,然后才执行自己。

    Container::Container(...): Component() {...}; //因为Component的构造函数可能不止一个,编译器不知道调用哪个,所以只会调用缺省构造函数,除非自己指定参数。

    析构由外而内
    Container 的析构函数首先执行自己,然后才调用Component的析构函数

    Container::~Container(...){... ~Component()};

    组装都是由内而外的,拆开肯定只能由外而内。


    Delegation(委托).Composition by reference;
    委托其实跟复合很像,说实在点也就是定义上有点区别。
    不过委托就是Composition(复合) by reference,看这个应该就能明白了。

    //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; 
    };
    //file String.cpp
    #include"String.hpp"
    namespace {
    class StringRep{
    friend class String;
    StringRep(const char * s);
    ~StringRep();
    int count;
    char * rep;
    };
    }
    
    String::String(){...}
    ...

    通过调用 StringRep指针来获取到字符串"Hello",通过下图就很明显能够看出。

     


    这种模式的优点就是无论你怎么修改StringRep 对客户所需要看到的Hello都不影响,甚至可以更换委托对象。维护和更新起来特别方便。
    可以说这两者之间就是 Handle 与 Body 的关系。


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

    语法上继承有3种方法,最常用的就是 :public ...
    其实struct和class是非常相似的,所以这里拿struct举例,继承是is-a的关系
    继承在面向对象中的概念来说,就是父类与子类,比如说人类分男人,女人,人类是父类,男人与女人是子类。
    拥有父类-人类的属性的同时,多了自己的属性。

    构造由内而外


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

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

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

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

    注意:base class 的 dtor必须是virtual,否则会出现 undefined behaviod
    养成习惯,每当创建的类有可能会作为基类衍生子类时,最好把这个类的析构函数设为虚函数(virtual)

  • 相关阅读:
    关于apache的动态与静态编译
    使用awk处理正则表达式时注意事项
    fedora下apache默认配置
    vim显示行号、语法高亮、自动缩进的设置
    简单介绍apahce内存管理机制
    处理路径上的小技巧
    Educational Codeforces Round 80 (Rated for Div. 2)
    web前端页面性能优化小结
    web标准—可用性、可维护性、可访问性
    雅虎团队经验:网站页面性能优化的 34条黄金守则
  • 原文地址:https://www.cnblogs.com/xiangqi/p/14276179.html
Copyright © 2011-2022 走看看