面向对象编程
类与类之间的关系:继承(Inheritance)、复合(Composition)和委托(Delegation)
复合
表示has a
:我里面有一个**东西;
template <class T>
class queue{
protected:
deque<T> c;//底层容器
public:
//以下完全利用变量c的操作函数完成
bool empty()const{return c.empty();}
void pop(){c.pop_front();}
void push(const value_type& x){c.push_back(x);}
};
queue
拥有了deque
,deque
已经很完美了,由于某些需求,使用queue
对deque
进行改装
- 表现出一种设计模式:
Adapter
- 构造和析构(此处
queue
为Container
,deque
为Component
)- 构造由内而外:
Container
的构造函数首先调用Component
的default
构造函数,然后才执行自己; - 析构由外而内:
Container
的析构函数首先执行自己,然后才调用Component
的析构函数;
- 构造由内而外:
委托
拥有指向某个类的指针,在想要调用时再调用(委托),也可称为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; //pimpl
};
//file String.cpp
#include "String.hpp"
namespace{
class StringRep{
friend class String;
StringRep(const char*s );
~StringRep();
int count;
char* rep;
};
}
String::String(){}
String
作为接口,而具体的实现在StringRep
中进行,即String
中有一个指针指向实现Stirng
中方法的类Handle/Body
(pImpl
)- 指针可以指向不同的实现类,称为编译防火墙,
String
可以一直不变,而采取不同的实现,即不同的StringRep
- 由于是指针连接,则双方生命周期不同。
- 共享相同的内容
- 若
a
修改Hello
,则copy
一份Hello
专门给a
进行修改,b
、c
不变
继承
表示 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;
}
- 父类的数据是被子类完整地继承下来
- 和虚函数搭配使用
- 构造和析构
- 构造由内而外:子类的构造函数首先调用基类的默认构造函数,然后才执行自己的构造函数
- 析构由外而内:子类的析构函数首先执行自己的析构函数,然后再调用基类的析构函数
- 基类的析构函数必须是
virtual
,否则会出现undefined behavior
继承下的虚函数(virtual functions)
在成员函数前加入 virtual
关键字
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{...};
-
non-virtual函数:你不希望子类重新定义(override,覆写)它;
-
virtual函数:你希望子类重新定义(override,覆写),你对它已有默认定义;
-
pure virtual函数:你希望子类一定要重新定义(override,覆写)它,你对它没有默认定义;
-
存在以下应用场景:
- 通过子类对象调用父类的函数,在父类函数中存在虚函数是在子类中给出的完整实现——
Template Method
- 应用:在不同操作系统中的打开文件的方式,父类给出基本的通用的方法,留下无法决定的使之成为虚函数,在子类中给出不同的实现。
- 通过子类对象调用父类的函数,在父类函数中存在虚函数是在子类中给出的完整实现——
三种关系的复合
继承和复合
- 重点在于构造函数和析构函数的执行次序
委托和继承
- 应用场景:PowerPoint开多个窗口
class Subject
{
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(this,m_value);
}
};
class Observer
{
public:
virtual void update(Subject* sub,int value)=0;
};
- 应用场景:文件系统;对应于设计模式中的
Composite