安全的方式来初始化派生类 [英] Safe way to initialize a derived class

查看:137
本文介绍了安全的方式来初始化派生类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个基类:

class CBase {
   public:
      virtual void SomeChecks() {}
      CBase() {
         /* Do some checks */
         SomeChecks();
         /* Do some more checks */
      }
};

和派生类:

class CDerived : public CBase {
   public:
      virtual void SomeChecks() { /* Do some other checks */ }
      CDerived() : CBase() {}
};

这种结构看起来有点怪异,但在我的例子中这是必需的,因为CBase做一些检查并且CDerived可以在它们之间混合一些检查。你可以看到它作为一种方式在构造函数中钩子函数。
这个构造的问题是,在构造CDerived的时候,构造一个CBase,并且没有意识到CDerived(因此重载的函数SomeChecks()没有被调用)。

This construction seems to be a bit weird but in my case this is required, because CBase does some checks and CDerived can mix some checks in between them. You can see it as a way to "hook" functions in the constructor. The problem with this construction is that while constructing CDerived first a CBase is constructed and there is no awareness of CDerived (so overloaded function SomeChecks() is not called).

我可以这样做:

class CBase {
   public:
      void Init() {
         /* Do some checks */
         SomeChecks();
         /* Do some more checks */
      }
      virtual void SomeChecks() {}
      CBase(bool bDoInit=true) {
         if (bDoInit) { Init(); }
      }
};
class CDerived : public CBase {
   public:
      virtual void SomeChecks() { /* Do some other checks */ }
      CDerived() : CBase(false) { Init() }
};

这不是真的安全,因为我想使用false参数的构造函数被保护,派生类可以调用它。
但是我必须创建第二个构造函数(即protected),并且使其他参数(可能未使用,因为在调用Init()时调用了构造函数)。

This isn't really safe, because I want the constructor with the false parameter be protected, so only derived classes can call it. But then I'll have to create a second constructor (that is protected) and make it take other parameters (probably unused because is constructor is called when Init() does not have to be called).

所以我很坚持这里。

EDIT 像这样:

class CBase {
   protected:
      void Init() { /* Implementation of Init ... */ }
      CBase() { /* Don't do the Init(), it is called by derived class */ }
   public:
      CBase() { Init(); }     // Called when an object of CBase is created
};
class CDerived : public CBase {
   public:
      CDerived() : CBase() { Init(); }
};

在我看来,不可能有两个具有相同参数的构造函数protected和public? / p>

It seems to me it is impossible to have 2 constructors with the same arguments being protected and public?

推荐答案

不允许在构造函数/析构函数中调用虚方法。

虚拟方法正在调用方法的最大派生版本,如果构造函数尚未完成,那么大多数派生数据未被正确初始化,因此这样做潜在地提供了使用无效对象的操作。

Calling virtual methods in the constructor/destructor is not allowed.
The though processes behind this is that virtual methods are calling the most derived version of a method and if the constructor has not finished then the most derived data has not been correctly initialized and therefore doing so potentially provides an opertunity for use of an invalid object.

您正在寻找的是PIMPL设计模式:

What you are looking for is the PIMPL design pattern:

class CBase { ... };
class CDerived: public CBase { ... }

template<typename T>
class PIMPL
{
    public:
        PIMPL()
            :m_data(new T)
        {
           // Constructor finished now do checks.
           m_data->SomeChecks();
        }
        // Add appropriate copy/assignment/delete as required.
    private:
        // Use appropriate smart pointer.
        std::auto_ptr<T>    m_data;
};
int main()
{
    PIMPL<CDerived>    data;
}

这篇关于安全的方式来初始化派生类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆