第三周
类之间的关系
面向对象的思想:
- inheritance(继承)
- composition(复合)
- Delegation(委托)
复合(has-a)
容器: queue:一端进一端出,deque:两端进,两端出
adapter:改造,适配:
对象适配器
将需要被适配的类的对象作为自己私有属性,实现目标类的接口。
类适配器
继承自需要被适配的类,并且实现目标类的接口。
构造函数和析构函数
- 构造由内而外
Container的构造函数先调用Component的默认构造函数,然后再执行自己的,默认不符合要求时,需要自己写。
- 析构函数由外而内
Container的析构函数首先执行自己的,然后再调用Component的析构函数
委托(Delegation)Composition by reference
包含另一个类的指针
String中只有接口(Handle),StringRep中才是真正的实现(Body):(编译防火墙)
class StringRep;
class String
{
public:
String();
String(const char * s);
String &operator=(const String& s);
~String();
private:
StringRep* rep; //pimpl
}
//file String.cpp
#include "String.hpp"
class StringRep
{
friend class String;
StringRep(const char* s);
~StringRep();
int count; //记录拷贝一样的次数。(共享一个StringRep),copy on write(写时给副本去写)
char* rep;
}
优点:接口对外不变,内部实现可以任意切换,不影响调用。
继承(is-a)
三种继承方式:public,private,protected
虚函数和继承结合使用
子类的对象中有父类的成分
构造由内而外
Derived的构造函数先调用Base的default构造函数,然后再执行自己的
析构由外而内:
Derived的析构函数首先执行自己,然后在调用Base的析构函数
Base的class的析构函数必须是virtual,否则会出现undefined behavior
虚函数与多态
函数继承的是调用权
三种:
- non-virtual函数,不希望derived class重新定义(override)的
- virtual 希望derived class重新定义
- pure virtual 希望derived class一定要重新定义,此函数没有默认定义(可以有定义)
class Shape
{
virtual void draw() const = 0; ///pure Virtual
virtual void error(const std::String & msg); ///impure virtual
int objectID() const; ///non-virtual
}
Template Method
通过子类对象调用父类函数,当父类的是虚函数,并且子类重定义过,执行子类的函数定义
功能最强大:
Delegate + inheritance
委托的相关设计
单数据源,多界面显示
//数据class:
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(Subgect* sub,int value)= 0;
}
文件系统:
//Composite
class Component //父类
{
int value;
public:
virtual void add(Component*){} //不能用纯虚
};
class Primitive:public Component //单体(文件)
{
//继承add,但是无实意
};
class Composite:public Component //组合
{
vector<Component*> vec; ///可以包含自己或者Primitive;
void add(Component* elem)
{c.push_back(elem);}
};
树状继承体系
Prototype:
#include<iostream>
enum imageType
{
LSAT,SPOT
};
class Image
{
public:
virtual void draw()=0;
static Image * find_AndClone(imageType);
protected:
virtual imageType returnType()=0;
virtual Image *clone()=0;
//As each subclass of Image is declared,it registers its prototype
statc void addPrototype(Image *image) ///添加子类到内存
{
_prototypes[_nextSlot++] = image;
}
private:
//addPrototype() save each registered prototype here
static Image *_prototype[10];
static int _nextSlot;
};
Image *image::prototypes[]; ///定义
int Image::_nextSlot;
//client calls this public static member function when it need an instance
//of an Image subclass
Image *Image::findAndClone() ///外部调用
{
for(int i= 0;i < _nextSlot;i++)
if (prototype[i]->returnType()==type)
return _prototype[i]->clone();
}
class LandSatImage:public Image
{
public:
imageType returnType()
{
return LSAT;
}
void draw()
{
cout << "LandSatImage::draw" << _id << endl;
}
//When clone() is called,call the one-argument ctor with a dummy arg
Image *clone() ///复制本身
{return new LandStaImage(1);}
protected:
//This is only called from clone()
LandSatImage(int dummy)
{
_id = _count++; ///复制数量
}
priate:
//Mechanism for imitializing an Image subclass - this causes the
//default ctor to be called,which registers the subclass's prototype
static LandSatImage landSatImage;
//This is only called when the private static data member is inited
LandSatImage()
{
addPrototype(this); ///构造函数里添加到父类
}
//Norminal 'state' per instance mechanism
int _id;
static int _count;
};
// Register the subclass's prototype
LandSatImage LandSatImage::_landSatImage;
//Initialize the "state" per instance mechanism
int LandSatImage::_cont = 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;
//Simulated stream of creation requests
const int NUM_IMAGES = 8;
imageType input[NUM_IMAGES] =
{
LSAT,LSAT,LSAT,SPOT,LSAT,SPOT,SPOT,LSAT
};
int main()
{
Image *image[NUM_IMAGES];
//Given an image type,find the right prototype ,and return a clone
for(int i= 0; i < NUM_IMAGES;i++)
images[i] = Image::findAndClone(input[i]);
//Demeonstrate that correct image objects have been cloned
for(i = 0;i < NUM_IMAGES;i++)
images[i]->draw();
//Free the dynameic memory
for(i = 0;i < NUM_IMAGES;i++)
delete images[i];
}