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:
MenuS开发者_开发百科creen : 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(...);
}
};
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
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.
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.
精彩评论