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

发布于 2024-11-03 06:50:48 字数 1042 浏览 0 评论 0原文

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

是否可以在 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(...);
     }
};

I have a base class MyScreen & I would like to always call the function initComponents() inside its constructor, even for sub classes of this class. But if the sub-class has overridden the initComponents() function, then I want MyClass to call the Sub-classes version of initComponents() not the super classes(MyScreen) version of initComponents().

Is it possible to do this from within MyClasses constructor?

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(...);
     }
};

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

却一份温柔 2024-11-10 06:50:48

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

相反,您应该由类的用户显式调用 initComponents 并标记它虚拟的

You shouldn't (or maybe even cannot) do that. The problem is that when constructing an object of your derived class, the base-class constructor is always called before the derived class's. This means that the derived object is not yet created, so its members will not be initialized (this will probabely also be valid for the v-table, so virtual function calls won't work). check this article

Instead you should call the initComponents by the user of your class explicitly and mark it virtual

苏大泽ㄣ 2024-11-10 06:50:48

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

No, you can't do this. The dynamic type of the object is always MyScreen inside MyScreen's constructor. You cannot call a MenuScreen function from inside it.

眼泪淡了忧伤 2024-11-10 06:50:48

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

#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);
        }

    };
};

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

Populating a resource by calling a virtual function is possible by using inner classes. Here is an example

#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

And here is how you can use it

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);
        }

    };
};

Just pay attention to inner classes used in both base and derived classes. The mutex locking and template stuff can be ignored for your case.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文