C++面向对象编程与类之间的关系(继承、复合、委托)

C++面向对象编程与类之间的关系(继承、复合、委托)

1、复合(Composition)

2、继承(Inheritance)

3、委托 (Delegation)

4、虚函数

一、复合(Composition)表示 has-a

示例代码:

template <class T, class Sequence = deque<T> >
class queue {
...
protected:
	Sequence c; // 底层的容器
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(); }
    // deque 是兩端可進出,queue 是末端進前端出(先進先出)
    void push(const value_type& x) { c.push_back(x); }
    void pop() { c.pop_front(); }
}

我们分析上面一段代码,队列queue中有一个双端队列Sequence对象,我们称这种关系为复合。队列中大部分的函数底层的实现我们是复用的双端队列对象Sequence的函数。

分析复合Composition下的构造和析构

构造由内而外:queue首先调用的是Sequence的默认的构造函数,然后再执行自己的构造函数。从内部到外部才扎实。

析构由外而内:queue先执行自己,然后再调用Sequence对象的析构函数。

从内存的角度看:queue对象的内存大小为类Sequence所占的内存的大小。

2、委托 (Delegation) Composition by reference.

示例代码:

// file String.cpp
#include "String.hpp"
namespace { 
class StringRep {
    friend class String;
    StringRep(const char* s);
    ~StringRep();
    int count; 
    char* rep;
};
}
String::String(){ ... }
...

//fileOne.hpp
class StringRep;
class String {
public:
    String();
    String(const char* s);
    String(const String& s);
    String &operator=(const String& s);
    ~String();
    . . . .
private:
	StringRep* rep; // pimpl
}

我们从上述代码可以得出,一个对象数据成员中包含另一个Class的指针,我们称这种关系为委托。

对外开出接口真正的实现可以再我们成员对象中去实现,编译防火墙,接口不改变,真正的实现可以变化。

3、继承(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;
};

子类对象拥有父类对象的成员函数和成员对象,子类对象里有父类的成分。

分析继承下的构造和析构

构造由内而外:先调用父类的默认构造函数,再执行自己

析构由外而内:先调用自己的析构函数,再调用父类的构造函数。

举一个例子:

class CDocument
{
 public:
 	void OnFileOpen() 
    {
      	... //一系列固定得操作
        Serialize();
		... //一系列固定得动作
    }

 virtual void Serialize() { }; 
};

class CMyDoc : public CDocument
{
public:
    virtual void Serialize()
    {
        //独有得读取文件格式的方式
        cout << "CMyDoc::Serialize()" << endl;
    }
};

int main()
{
     CMyDoc myDoc; // 调用文件的方式[File/Open] 
     myDoc.OnFileOpen();
     return 0;
}

考虑继承加上复合情况下的构造和析构?

构造由内而外:先调用父类的默认构造函数,然后调用子类成员的构造函数,再执行自己

析构由外而内:先调用自己的析构函数,然后调用子类成员的析构函数 最后调用父类的构造函数。

4、虚函数

1、non-virtual 普通函数:你不希望子类重新定义该函数 (override, 重写) 它.

2、virtual 虚函数:你希望子类重新定义(override, 重写) 它,且你已经对它头默认的定义。

3、pure virtual 纯虚函数:你希望 子类一定要重新定义(override, 重写) 它,你对它没有默认的定义。

示例代码如下:

class Shape {
public:
    virtual void draw( ) const = 0;   			//纯虚函数
    virtual void error(const std::string& msg);	//虚函数
    int objectID( ) const;						//普通函数
	...
};

注意:较为复杂的情况,委托加上继承

示例一个观察者模型例子:

class Subject
{
private:
    int m_value;
    vector<Observer*> m_views;
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(m_value);
    }
}

class Observer
{
public:
	virtual void update(int value) = 0;
    ...
};

class Observer1: public Observer
{
public:
    Observer1(Subject *model, int div)
    {
        model->attach(this);
        m_div = div;
    }

    /* virtual */void update(int v)
    { … }
    ...
};

class Observer2: public Observer
{
public:
    Observer1(Subject *model, int div)
    {
        model->attach(this);
        m_div = div;
    }
    /* virtual */void update(int v)
    { … }
    ...
};

{
    Subject subj;  //调用 
    Observer1 o1(&subj, 4);
    Observer1 o2(&subj, 3);
    Observer2 o3(&subj, 3);
    subj.set_val(14);
}
//此例子试用于多视图现实的时候可以使用,想想是不是很符合场景

委托加上继承还有很多设计,这里不一一去书写了,后面的文章中会写到,加油又是干劲十足的一天。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值