计算机二级C基础:虚拟构造函数的用处
来源:优易学  2011-12-9 21:18:28   【优易学:中国教育考试门户网】   资料下载   IT书店

  从字面来看,谈论“虚拟构造函数”没有意义。当有一个指针或引用,但是不知道其指向对象的真实类型是什么时,可以调用虚拟函数来完成特定类型(type-specific)对象的行为。仅当还没拥有一个对象但是又确切地知道想要的对象的类型时,才会调用构造函数。那么虚拟构造函数又从何谈起呢?
  很简单。尽管虚拟构造函数看起来好像没有意义,其实它们有非常大的用处.例如,假设编写一个程序,用来进行新闻报道的工作,每一条新闻报道都由文字或图片组成。可以这样管理它们:
  class NLComponent {//用于 newsletter components
  public:// 的抽象基类
  ... //包含至少一个纯虚函数
  };
  class TextBlock: public NLComponent {
  public:
  ... // 不包含纯虚函数
  };
  class Graphic: public NLComponent {
  public:
  ... // 不包含纯虚函数
  };
  class NewsLetter { // 一个 newsletter 对象
  public:// 由NLComponent 对象
  ... // 的链表组成
  private:
  list components;
  };
  在NewsLetter中使用的list类是一个标准模板类(STL)。list类型对象的行为特性有些象双向链表,尽管它没有以这种方法来实现。对象NewLetter不运行时就会存储在磁盘上。为了能够通过位于磁盘的替代物来建立Newsletter对象,让NewLetter的构造函数带有istream参数是一种很方便的方法。当构造函数需要一些核心的数据结构时,它就从流中读取信息:
  class NewsLetter {
  public:
  NewsLetter(istream& str);
  ...
  };
  此构造函数的伪代码是这样的:
  NewsLetter::NewsLetter(istream& str)
  {
  while (str) {
  从str读取下一个component对象;
  把对象加入到newsletter的 components对象的链表中去;
  }
  }
  或者,把这种技巧用于另一个独立出来的函数叫做readComponent,如下所示:
  class NewsLetter {
  public:
  ...
  private:
  // 为建立下一个NLComponent对象从str读取数据,
  // 建立component 并返回一个指针。
  static NLComponent * readComponent(istream& str);
  ...
  };
  NewsLetter::NewsLetter(istream& str)
  {
  while (str) {
  // 把readComponent返回的指针添加到components链表的最后,
  // \"push_back\" 一个链表的成员函数,用来在链表最后进行插入操作。
  components.push_back(readComponent(str));
  }
  }
  考虑一下readComponent所做的工作。它根据所读取的数据建立了一个新对象,或是TextBlock或是Graphic。因为它能建立新对象,它的行为与构造函数相似,而且因为它能建立不同类型的对象,我们称它为虚拟构造函数。虚拟构造函数是指能够根据输入给它的数据的不同而建立不同类型的对象。虚拟构造函数在很多场合下都有用处,从磁盘(或者通过网络连接,或者从磁带机上)读取对象信息只是其中的一个应用。
  还有一种特殊种类的虚拟构造函数――虚拟拷贝构造函数――也有着广泛的用途。虚拟拷贝构造函数能返回一个指针,指向调用该函数的对象的新拷贝。因为这种行为特性,虚拟拷贝构造函数的名字一般都是copySelf,cloneSelf或者是象下面这样就叫做clone。很少会有函数能以这么直接的方式实现它:
  class NLComponent {
  public:
  // declaration of virtual copy constructor
  virtual NLComponent * clone() const = 0;
  ...
  };
  class TextBlock: public NLComponent {
  public:
  virtual TextBlock * clone() const// virtual copy
  { return new TextBlock(*this); } // constructor
  ...
  };
  class Graphic: public NLComponent {
  public:
  virtual Graphic * clone() const// virtual copy
  { return new Graphic(*this); } // constructor
  ...
  };

  正如我们看到的,类的虚拟拷贝构造函数只是调用它们真正的拷贝构造函数。因此“拷贝”的含义与真正的拷贝构造函数相同。如果真正的拷贝构造函数只做了简单的拷贝,那么虚拟拷贝构造函数也做简单的拷贝。如果真正的拷贝构造函数做了全面的拷贝,那么虚拟拷贝构造函数也做全面的拷贝。如果真正的拷贝构造函数做一些奇特的事情,象引用计数或copy-on-write,那么虚拟构造函数也这么做。
  注意上述代码的实现利用了最近才被采纳的较宽松的虚拟函数返回值类型规则。被派生类重定义的虚拟函数不用必须与基类的虚拟函数具有一样的返回类型。如果函数的返回类型是一个指向基类的指针(或一个引用),那么派生类的函数可以返回一个指向基类的派生类的指针(或引用)。这不是C++的类型检查上的漏洞,它使得有可能声明象虚拟构造函数这样的函数。这就是为什么TextBlock的clone函数能够返回TextBlock*和Graphic的clone能够返回Graphic*的原因,即使NLComponent的clone返回值类型为NLComponent*。
  在NLComponent中的虚拟拷贝构造函数能让实现NewLetter的(正常的)拷贝构造函数变得很容易:
  class NewsLetter {
  public:
  NewsLetter(const NewsLetter& rhs);
  ...
  private:
  list components;
  };
  NewsLetter::NewsLetter(const NewsLetter& rhs)
  {
  // 遍历整个rhs链表,使用每个元素的虚拟拷贝构造函数
  // 把元素拷贝进这个对象的component链表。
  for (list::const_iterator it =
  rhs.components.begin();
  it != rhs.components.end();
  ++it) {
  // \"it\" 指向rhs.components的当前元素,调用元素的clone函数,
  // 得到该元素的一个拷贝,并把该拷贝放到
  // 这个对象的component链表的尾端。
  components.push_back((*it)->clone());
  }
  }

[1] [2] 下一页

责任编辑:小草

文章搜索:
 相关文章
热点资讯
资讯快报
热门课程培训