Parent类可以调用其子类版本的函数

时间:2011-04-22 10:40:02

标签: c++ inheritance override

我有一个基类MyScreen&我想始终在其构造函数中调用函数initComponents(),即使对于此类的子类也是如此。但是如果子类重写了initComponents()函数,那么我希望MyClass调用initComponents()的子类版本而不是initComponents()的超类(MyScreen)版本。 / p>

是否可以在MyClasses构造函数中执行此操作?

class MyScreen
{
  public:
     MyScreen()
     {
        // a child of this class (& any instance of this class) should always call the initComponents() from this constructor
        initComponents(); 
     } 

     void initComponents()
     {
         // initialise mainLayout, etc, usually this function wont be overridden, sometimes it will be
     }

  protected:
      Layout *mainLayout;
};

class MenuScreen : public MyScreen
{
  public:
     MenuScreen : public MyScreen()
     {
        // I know I could just call initComponents from here, but this is just an example, somethings must be called from the base class
     } 

     void initComponents()
     {
         // create layout, set main layout etc.
         mainLayout = new MenuLayout(...);
     }
};

3 个答案:

答案 0 :(得分:3)

你不应该(或者甚至不能)这样做。问题是,在构造派生类的对象时,总是在派生类之前调用​​基类构造函数。这意味着尚未创建派生对象,因此其成员将不会被初始化(这可能对v表也有效,因此虚函数调用将不起作用)。检查this article

相反,您应该明确地由您的类的用户调用initComponents并将其标记为虚拟

答案 1 :(得分:1)

不,你不能这样做。对象的动态类型始终是MyScreen的构造函数中的MyScreen。你不能从里面调用MenuScreen函数。

答案 2 :(得分:0)

通过使用内部类可以通过调用虚函数来填充资源。这是一个例子

#ifndef CLAZYSTATICRESOURCINITIALIZATIONASPECT_H
#define CLAZYSTATICRESOURCINITIALIZATIONASPECT_H

#include <boost/thread/mutex.hpp>

template <typename R>
class CLazyStaticResourceInitialization
{
public:

    /**
     * Destructor
     */
    virtual ~CLazyStaticResourceInitialization()
    {
    }

protected:

    /**
     * Internal class used for calling  virtual function from constructor
     */
    struct parent_virtual
    {
        /**
         * Virtual destructor
         */
        virtual ~parent_virtual ()
        {
        }
        /**
         * Virtual method implemented by parent class is necessary
         */
        virtual void initializeOnce () const
        {
        }
    };

    /**
     * Constructor that can call a virtual function of the parent 
     * @param obj specifies the virtual function
     */
    CLazyStaticResourceInitialization(const parent_virtual& obj )
    {
        boost::mutex::scoped_lock scoped_lock(m_Mutex);

        //Initialize the resource only once
        if (isInitialized () == false)
        {
            obj.initializeOnce ();

            setInitialized ();
        }
    }

    /**
     * Returns if any instance of this class has been initialized or not 
     * @return true if initialized, false otherwise
     */
    bool isInitialized () const
    {
        return m_bInitialized;;
    }

    /**
     * Returns if any instance of this class has been initialized or not 
     */
    void setInitialized ()
    {
        m_bInitialized = true;
    }

protected:

    /**
     * The flag that indicates whether this class is initialized or not
     */
    static volatile bool    m_bInitialized;

    /**
     * The resource instance
     */
    static R        m_Resource;

    /** 
     * The mutex to protect initialized flag
     */
    static boost::mutex     m_Mutex;


};

//Assume that this  class is not initialized in the beginning
template <typename R> volatile bool CLazyStaticResourceInitialization<R>::m_bInitialized    = false;

//Create a static instance of resource
template <typename R> R CLazyStaticResourceInitialization<R>::m_Resource;

//Create a static instance of mutex
template <typename R> boost::mutex CLazyStaticResourceInitialization<R>::m_Mutex;


#endif

以下是如何使用它

class CTestLazyInitialized : public CLazyStaticResourceInitialization <std::vector<int> >
{
public:
    CTestLazyInitialized():
    CLazyStaticResourceInitialization<std::vector<int> >(lazyderived_virtual())
    {
    }

    unsigned int size ()
    {
        return this->m_Resource.size ();
    }
protected:

    struct lazyderived_virtual : public CLazyStaticResourceInitialization <std::vector<int> >::parent_virtual
    {

        lazyderived_virtual ()
        {
        }

        void initializeOnce () const
        {
            m_Resource.push_back (1);
        }

    };
};

注意基类和派生类中使用的内部类。对于您的情况,可以忽略互斥锁定和模板内容。