//假如写一个软件,用来处理时事新闻,其内容由文字和图形构成
class NTComponent{ //抽象基类,用于时事消息的组件
public: //其中至少含有一个纯虚函数
...
};
class TextBlock:public NTComponent{
public:
... //没有内含有任何纯虚函数
};
class Graphic : public NTComponent{
public:
... //没有内含有任何纯虚函数
};
class NewsLetter{ //一份时事通讯是有一系列的NTComponent对象构成
public:
...
private:
list<NTComponent*> components;
};
//NewsLetter对象尚未开始运作的时候,可能存储于磁盘中
//让NewsLetter拥有一个constructor并用istream作为自变量
//这个constructor将从stream读取数据以便产生必要的核心数据结构:
class NewsLetter{
public:
NewsLetter(istream& str);
...
};
NewsLetter::NewsLetter(istream& str)
{
while(str)
{
read the next component object;
add the object to the list of
this newsletter's components;
}
}
//如果将棘手的东西搬移到另一个名为readComponent的函数:
class NewsLetter{
public:
...
private:
static NTComponent* readComponent(istream& str);
...
};
NewsLetter::NewsLetter(istream& str)
{
while(str)
{
//将readComponent返回的指针加到component list尾端,
//“push_back”是一个list member function,用来将对象安插
//到list尾端
components.push_back(readComponent(str));
}
}
此时readComponent产生新对象,所以行为仿若constructor,但是它能够产生不同类型的对象,所以我们称之它为一个virtual constructor。
virtual constructor:
- 某种函数,视其获得的输入,可产生不同的类型对象;
- 在许多情况下有用,比如从磁盘(或网盘或磁带等)读取对象信息。
virtual copy constructor:
- 返回一个指针,指向其调用者(某对象)的一个新副本;
- 基于这种行为,virtual copy constructors通常以copySelf或cloneSelf命名,或者像下面一样命令为clone。
class NLComponent{
public:
//声明 virtual copy constructor
virtual NLComponent* clone() const = 0;
...
};
class TextBlock:public NLComponent{
public:
virtual TextBlock* clone() const //virtual copy constructor
{
return new TextBlock(*this);
}
...
};
class Graphic:public NLComponent{
public:
virtual Graphic* clone() const //virtual copy constructor
{
return new Graphic(*this);
}
...
};
class NewsLetter{
public:
NewsLetter(const NewsLetter& rhs);
...
private:
list<NLComponent*> components;
};
NewsLetter::NewsLetter(const NewsLetter& rhs)
{
//迭代遍历rhs list,运用每个元素的virtual copy constructor,
//将元素复制到对象的component list中。
for(list<NLComponent*>::const_iterator it = rhs.components.begin();
it != rhs.components.end(),++it)
{
components.push_back((*it)->clone());
}
}
写一个虚函数做实际工作,再写一个什么都不做的非虚函数,只负责调用虚函数;为了避免此巧妙安排蒙受函数调用所带来的成本,也可以将非虚函数inline化。
//为TextBlock和Graphic实现出output操作符
class NLComponent{
public:
virtual ostream& print(ostream& str) const = 0;
};
class TextBlock:public NLComponent{
public:
virtual ostream& print(ostream& str);
};
class Graphic:public NLComponent{
public:
virtual ostream& print(ostream& str);
};
inline ostream& operator<<(ostream& s,const NLComponent& c)
{
return c.print(s);
}