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)

原文地址:https://www.cnblogs.com/xiangqi/p/14276179.html