Chinaunix首页 | 论坛 | 博客
  • 博客访问: 308696
  • 博文数量: 94
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 202
  • 用 户 组: 普通用户
  • 注册时间: 2014-08-08 20:07
文章分类

全部博文(94)

文章存档

2017年(19)

2016年(30)

2015年(12)

2014年(33)

我的朋友

分类: LINUX

2017-05-12 17:37:23

编写代码时,不应该在构造/析构函数中调用virtual函数,因为这样做不会给你预想的结果!例如我们有以下几个类:

点击(此处)折叠或打开

  1. class Transaction {
  2. public:
  3.     Transaction();
  4.     virtual void logTransaction() const = 0; //log different obj operations
  5.     //...
  6. };

  7. Transaction::Transaction()
  8. {
  9.     //...
  10.     logTransaction();
  11. }

  12. class BuyTransaction: public Transaction {
  13. public:
  14.     virtual void logTransaction() const;
  15.     //...
  16. };

  17. BuyTransaction bt;

基类Transaction构造函数内虚函数的用意在于,每当被不同类继承时,依照不同类特性对交易操作进行log记录。
然而,当我们创建一个BuyTransaction 对象时,基类Transaction对象先被创建,此时继承类BuyTransaction对象还没有被创建,一切有关继承类的成员都还未定义,虚函数logTransaction实际上是基类Transaction的成员(C++编译器不会将virtual指针指定为还不存在的函数),而并非BuyTransaction的成员
同样的道理也适用于析构函数。

既然在构造函数中不能调用虚函数来实现适用于不同类版本的logTransaction函数,那么该如何实现?
通常有一种做法是,在Transaction类内将logTransaction实现为non-virtual函数,然后要求derived-class构造函数传递必要信息给Transaction构造函数。
而后那个构造函数便可安全地调用non-virtual logTransaction函数。
比如:

点击(此处)折叠或打开

  1. class Transaction {
  2. public:
  3.     explicit Transaction(const std::string &logInfo);
  4.     void logTransaction(const std::string &logInfo) const;
  5.     //...
  6. };

  7. Transaction::Transaction(const std::string & logInfo)
  8. {
  9.     //...
  10.     logTransaction(logInfo);
  11. }

  12. class BuyTransaction: public Transaction {
  13. public:
  14.     BuyTransaction(parameters): Transaction(createLogString(parameters))
  15.     {
  16.         //...
  17.     }
  18.     //...

  19. private:
  20.     static std::string createLogString(parameters);
  21. };
换句话说,由于你无法使用virtual函数从base class向下调用,在构造期间,你可以藉由“另derived class将必要的信息传递给base class的构造函数”替换加以弥补之。

同时,这里需要注意private 里面static函数createLogString的应用。令此函数为static,也就不可能意外指向“初期BuyTransaction对象内尚未初始化的成员变量

阅读(1293) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~