条款M25:将构造函数和非成员函数虚拟化

1、虚拟构造函数:
应用场景:根据从磁盘读取的不同对象信息,构造不同对象。

//.h
class NLComponent {               //用于 newsletter components  
public:                           // 的抽象基类  
  ...                             //包含至少一个纯虚函数 
}; 
class TextBlock: public NLComponent { 
public: 
  ...                             // 不包含纯虚函数 
};  
class Graphic: public NLComponent { 
public: 
  ...                             // 不包含纯虚函数 
}; 

class NewsLetter {                // 一个 newsletter 对象 
public:                           // 由 NLComponent 对象 
  ...                             // 的链表组成 
  NewsLetter(istream& str); 
private: 
  list<NLComponent*> components; 
  // 为建立下一个 NLComponent 对象从 str 读取数据, 
  // 建立 component 并返回一个指针。 
  static NLComponent * readComponent(istream& str); 
}; 

//.cpp
NewsLetter::NewsLetter(istream& str) 
{ 
  while (str) { 
      // 把 read Component 返回的指针添加到 components 链表的最后, 
      // "push_back" 一个链表的成员函数,用来在链表最后进行插入操作。 
      components.push_back(readComponent(str)); 
  } 
}

注:read Component()的实现可详见《汤姆.斯旺 C++编程秘诀》。
虚拟构造函数本质:只是根据参数类型不同调用不同的构造函数。

2、虚拟拷贝构造函数:
应用场景:根据不同对象自动调用各自不同的复制构造函数。自动调用过程给人以虚函数调用的感觉。

//.h
class NLComponent {  //抽象类
public: 
  // declaration of virtual copy constructor 
  virtual NLComponent* clone() const = 0; 
  ...  
};  
class TextBlock: public NLComponent { //派生类1
public: 
	关键代码段:
  virtual TextBlock * clone() const         // virtual copy 
  { return new TextBlock(*this); }          // constructor 
  ...  
};  
class Graphic: public NLComponent {  //派生类2
public: 
  virtual Graphic * clone() const            // virtual copy 
  { return new Graphic(*this); }             // constructor 
  ...  
}; 
class NewsLetter { 
public: 
  NewsLetter(const NewsLetter& rhs); 
  ...  
private: 
  list<NLComponent*> components; 
};
  
//.cpp
NewsLetter::NewsLetter(const NewsLetter& rhs) 
{ 
  // 遍历整个 rhs 链表,使用每个元素的虚拟拷贝构造函数 
  // 把元素拷贝进这个对象的 component 链表。 
  // 有关下面代码如何运行的详细情况,请参见条款 M35. 
  for (list<NLComponent*>::const_iterator it = 
          rhs.components.begin(); 
       it != rhs.components.end(); 
       ++it) {  
  // "it" 指向 rhs.components 的当前元素,调用元素的 clone 函数, 
  // 得到该元素的一个拷贝,并把该拷贝放到 
  // 这个对象的 component 链表的尾端。 
    components.push_back(it->clone()); 
  } 
}

类的虚拟复制构造函数本质:只是通过编写其他虚函数,在其中调用它们真正的复制构造函数

3、虚拟化非成员函数:
如为 TextBlock 和 Graphic 对象实现一个输出操作符:
a) 不好的做法:将cout作为参数重载<<

//.h
class NLComponent { 
public: 
  // 对输出操作符的不寻常的声明 
  virtual ostream& operator<<(ostream& str) const = 0; 
  ... 
};  
class TextBlock: public NLComponent { 
public: 
  // 虚拟输出操作符(同样不寻常) 
  virtual ostream& operator<<(ostream& str) const; 
};  
class Graphic: public NLComponent { 
public: 
  // 虚拟输出操作符 (同样不寻常) 
  virtual ostream& operator<<(ostream& str) const; 
}; 

//.cpp
TextBlock t; 
Graphic g;  
...  
t << cout;     // 通过 virtual operator<< 把 t 打印到 cout 中。 不寻常的语法 
g << cout;     // 与常规cout<<t; 不同

b) 不好的做法:自定义输出函数如print

//.h
class NLComponent { 
public: 
  // 自定义输出函数不好看
  virtual ostream& print(ostream& s) const = 0;
  ... 
};  
class TextBlock: public NLComponent { 
public: 
  virtual ostream& print(ostream& s) const; 
};  
class Graphic: public NLComponent { 
public: 
   virtual ostream& print(ostream& s) const;  
}; 
inline ostream& operator<<(ostream& s, const NLComponent& c) 
{ 
  return c.print(s); 
}
//.cpp
TextBlock t; 
Graphic g;  
...  
t.print();     
g.print(); 

c) 好的做法:虚拟化非成员函数

//.h
class NLComponent { 
public: 
  virtual ostream& print(ostream& s) const = 0; 
  ...  
};  
class TextBlock: public NLComponent { 
public: 
  virtual ostream& print(ostream& s) const; 
  ...  
};  
class Graphic: public NLComponent { 
public: 
  virtual ostream& print(ostream& s) const; 
  ...  
};  
inline 
ostream& operator<<(ostream& s, const NLComponent& c) 
{ 
  return c.print(s); 
}

//.cpp
TextBlock t; 
Graphic g;  
...  
cout<<t<<g;  //好的做法

虚拟化非成员函数本质:编写一个虚函数来完成工作,然后再写一个非虚函数,它什么也不做只是调用这个虚拟函数。为了避免这个句法花招引起函数调用开销,可以内联这个非虚拟函数。

总结:

1、通过虚拟构造函数,可以实现根据参数类型不同调用不同的构造函数。
2、通过类的虚拟复制构造函数,实现根据不同对象自动调用各自不同的复制构造函数。过程为编写其他虚函数,在其中调用它们真正的复制构造函数,自动调用过程给人以虚函数调用的感觉。
3、通过虚拟化非成员函数,实现根据不同对象自动调用各自不同的函数。过程为编写一个虚函数来完成工作,然后再写一个非虚函数,它什么也不做只是调用这个虚拟函数。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值