I use public constructors when I have embedded FormViews derived from a
class which lives in a static library.
There is a bit of jiggery-pokey involved but it works.
"Joseph M. Newcomer" <newcomer@flounder.com> wrote in message
See below...
On Thu, 22 May 2008 03:16:01 -0700, sawer <sawer@discussions.microsoft.com> wrote:
Hi
I want to ask you about logic behind the protected constructors in MFC.
Firstly i want to give an example. This make easier to explain the problem.
I added a class which is driven from CView class. And i want to show it when
clicked "View->New Window" menu.
***********************
#pragma once
// code view
class code : public CView
{
DECLARE_DYNCREATE(code)
protected:
code(); // protected constructor used by dynamic creation
virtual ~code();
public:
virtual void OnDraw(CDC* pDC); // overridden to draw this view
#ifdef _DEBUG
virtual void AssertValid() const;
#ifndef _WIN32_WCE
virtual void Dump(CDumpContext& dc) const;
#endif
#endif
protected:
DECLARE_MESSAGE_MAP()
};
*************************
I can not call like this:
CView* pView = (CView*) new code; // error C2248 cannot access protected
member
****
That's correct. You cannot access the protected member. Why would you want to? Doing
'new code' makes no sense. If you want a new view, you would create the new view using
the supported interfaces, which not only create the view, but initialize it properly.
****
1-) Why are the wizard declare classes constructors protected or private?
What is the benefit/logic? For example If i add class which is derived from
CEdit with wizard, its constructors is declared public but if it is derived
from CEditView its constructor is declared protected. Why is that so?
****
Because view constructors are protected for a reason: you are not supposed to be calling
them. So, deliberately, they are made protected. The rationale is that you do not know
how to create a view; it is more than just allocating an object. So don't do it. Do it
the right way.
****
2-)Is changing protected to public best way?
****
No, it will do the wrong thing, and you will not be happy with the result. Why are you
confusing the concept of "create a new view" with "use the new operator"?
****
3-) Where must i handle the menu selection, i mean creating new form. In
MainFrm.cpp or something else?
****
I usually do this in the CMainFrame class; here's the code
I did this from the mainfrm.cpp file. The code goes like this:
Add a protected variable to the mainframe class:
CMultiDocTemplate * GreenTemplate;
In the CMainFrame::CMainFrame constructor, clear it out
GreenTemplate = NULL;
Add a new protected class member function
CDocument * GetCurrentDocument();
For symmetry, I added an additional variable
CMultiDocTemplate * RedTemplate;
and set it to NULL as well.
Create a new CView-derived class, in my case CGreenView (the names have been sanitized to
protected certain secure information).
The default view is a Red view, as exemplified by the standard InitInstance code:
pDocTemplate = new CMultiDocTemplate(IDR_RedViewTYPE,
RUNTIME_CLASS(CMultiViewDoc),
RUNTIME_CLASS(CChildFrame), // custom MDI child frame
RUNTIME_CLASS(CRedView));
if (!pDocTemplate)
return FALSE;
AddDocTemplate(pDocTemplate);
I added the following:
a new menu
#define IDR_GreenViewTYPE (xxx)
where xxx is a resource number you have not already used. In my case it was 130. It has
to have an ICON of that ID, and a STRINGTABLE resource of that ID, so the ID numeric value
cannot be used already in either a string, icon, or menu context.
I added to the Window menu of the exisiting IDR_RedViewTYPE the item
&Green View = ID_WINDOW_GREENVIEW
and to the new menu for the IDR_GreenViewTYPE the item
&Red View = ID_WINDOW_REDVIEW
I Created an icon of the ID IDR_GreenTYPE.
In mainfrm.cpp, I added the handler to create a Green View:
CDocument * CMainFrame::GetCurrentDocument()
{
CMDIFrameWnd * frame = (CMDIFrameWnd*)AfxGetApp()->m_pMainWnd;
if(frame == NULL)
return NULL;
CMDIChildWnd * child = (CMDIChildWnd *)frame->GetActiveFrame();
if(child == NULL)
return NULL;
CView * view = child->GetActiveView();
if(view == NULL)
return NULL;
CDocument * doc = view->GetDocument();
return doc;
} // CMainFrame::GetCurrentDocument
void CMainFrame::OnWindowGreenview()
{
if(GreenTemplate == NULL)
GreenTemplate = new CMultiDocTemplate(IDR_GreenViewTYPE,
RUNTIME_CLASS(CMultiViewDoc),
RUNTIME_CLASS(CChildFrame),
RUNTIME_CLASS(CGreenView));
CMultiViewDoc * doc = (CMultiViewDoc *)GetCurrentDocument();
CFrameWnd * frame = GreenTemplate->CreateNewFrame(doc, NULL);
if(frame != NULL)
{ /* frame created */
frame->InitialUpdateFrame(doc, TRUE);
} /* frame created */
}
void CMainFrame::OnUpdateWindowGreenview(CCmdUI *pCmdUI)
{
CMultiViewDoc * doc = (CMultiViewDoc *)GetCurrentDocument();
pCmdUI->Enable(doc != NULL);
}
And one for a Red view:
void CMainFrame::OnWindowRedview()
{
if(RedTemplate == NULL)
RedTemplate = new CMultiDocTemplate(IDR_RedViewTYPE,
RUNTIME_CLASS(CMultiViewDoc),
RUNTIME_CLASS(CChildFrame),
RUNTIME_CLASS(CRedView));
CMultiViewDoc * doc = (CMultiViewDoc *)GetCurrentDocument();
CFrameWnd * frame = RedTemplate->CreateNewFrame(doc, NULL);
if(frame != NULL)
{ /* frame created */
frame->InitialUpdateFrame(doc, TRUE);
} /* frame created */
}
void CMainFrame::OnUpdateWindowRedview(CCmdUI *pCmdUI)
{
CMultiViewDoc * doc = (CMultiViewDoc *)GetCurrentDocument();
pCmdUI->Enable(doc != NULL);
}
To the destructor CMainFrame::~CMainFrame add
delete RedTemplate;
delete GreenTemplate;
****
If you help me to understand this concept i will be very glad
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm