simdoc

Consider the following code:

#include <iostream>
class CVA
{
public:
};

class CVB : virtual public CVA
{
public:
};

class CB0
{
public:
   CB0() {}
   void TestFunc() {
      std::cout << _T(
"In CB0::TestFunc") << std::endl;
   }
};

class CB1 : public CB0
{
public:
   CB1() {}
   void TestFunc() {
      std::cout << _T(
"In CB1::TestFunc") << std::endl;
   }
};

class CD : public CB1, public CVB
{
public:
   CD() {}
   void TestFunc() {
      std::cout << _T(
"In CD::TestFunc") << std::endl;
   }
};

int _tmain(int argc, _TCHAR* argv[])
{
   typedef void (CB0::*PFCB0)(void);
   typedef void (CB1::*PFCB1)(void);

   //
   // Should the following line generate compiler warning C4407:
   PFCB1 pfCB1 = (PFCB1)
static_cast<void (CB1::*)(void)>(&CD::TestFunc);
   PFCB0 pfCB0 = (PFCB0)pfCB1;

   CD d;
   (d.*pfCB0)();
   return 0;
}

Should the indicated line generate the compiler warning C4407: cast between different pointer to member representations, compiler may generate incorrect code   This warning did not occur in VC++ 2003.  Note the pfCB0 assignment line generates no warnings and the (d.*pfCB0)() function call calls the CD member function as desired.

If the virtual inheritance for class CVA is removed, no warnings are issued as well.  Can someone explain what is going on

Thanks.



Re: Visual C++ Language Should generate C4407 warning in VC++ 2005??

Jonathan Caves MSFT

This is slightly complicated and is really an artifact of how the original Microsoft C++ compiler was designed.

You need to understand that a pointer-to-member is not just the address of the member in question: instead you can think of it as a series of one or more elements that when combined at runtime will correctly navigate to the required member. In the case of single-inheritance (and in most multiple-inheritance cases) the only element you require is in fact the address of the member so in these cases a pointer-to-member is just the address of the member.

In the case of virtual-inheritance things get more complicated: in this case the elements include how to nagivate to the appropriate base-class (in the case of virtual functions + virtual inheritance things get even more complicated).

CB1 is a single-inheritance class so it can have the simple pointer-to-member representation. CD is a virtual-inheritance class and so it needs a more complicated representation.

Trying adding the following to the main function in your program:

typedef void (CD::*PFCD)();

std::cout << sizeof(PFCB1) << std::endl;
std::cout << sizeof(PFCD) << std::endl;


And then compile it and run it and you should see:

4
12


So you can see what the compiler is complaining about: you are assigning an object of size 12 to an object of size 4 - hence the C4407 diagnostic. Luckily in most cases this works: but it can cause hard to track down runtime bugs: hence the warning.

There is a way to avoid this problem: that is to tell the compiler to be pessimistic and to not "optimize" pointers-to-members. There is a command-line switch to do this: /vmg. Here is the MSDN topic on it:

http://msdn.microsoft.com/library/default.asp url=/library/en-us/wcechp40/html/ccrefVmg-UseFullGeneralityForPointers.asp

If I compile your code with this switch I don't get the warning (as the representations are now the same) but the output of the sizeof expressions is different:

16
16


This is because the compiler is using the most general pointer-to-member representation - and this takes up more space.

If you want all the gory details about pointer-to-members in C++ in general this is a great article:

http://www.codeproject.com/cpp/FastDelegate.asp

It also provides a better solution than using raw pointers-to-members.





Re: Visual C++ Language Should generate C4407 warning in VC++ 2005??

simdoc

Jonathan:

Thanks for the information.  It really helped.  I will read the information you referenced.

I guess my questions are:

1) Can this setting be controlled on a class by class basis since I have a large program and don't mind the overhead on the few affected classes but would rather not have it on the entire application.

2) Where I'm actually seeing these messages is in the message map of an MFC dialog class.  MFC is doing basically the same thing as my sample.    In my case, class CB1 is actually CDialog and CVB is some general class with a similar virtual inheritance structure that I need in the dialog.  I receive the warnings on ON_CBN_SELCHANGE() and other macros in the message map.  I derive from the CWnd class first as is required for multiple inheritance with MFC.  Is there some class declaration I can use to ensure no problems

3) Why did the VC++ 2003 compiler not generate these warnings   Did something change in the implementation

Again, thanks for the information thus far.




Re: Visual C++ Language Should generate C4407 warning in VC++ 2005??

Martin Richter

to 2): No! The MFC has a completely different approach to handle messages! The message map is evealuated by a virtual function GetMessageMap. But the rest is are pure non virtual function calls. Also the basic mechanisms are different. If you want to program it by yourself look at the link Jonathan gave to you. It is a really good article.

to 3): The VS.NET 2003 compiler is good, but not a sgood as the Vs.NET 2005 compiler. Smile




Re: Visual C++ Language Should generate C4407 warning in VC++ 2005??

Jonathan Caves MSFT

1) Unfortunately there is not way to do this in the language - if you want to stick to raw pointer-to-members then the /vmg switch is your only option.




Re: Visual C++ Language Should generate C4407 warning in VC++ 2005??

Laitu

I had similar problem with MFC
the code looks like following:

IMPLEMENT_DYNCREATE(CMainView, CContainerView)

BEGIN_MESSAGE_MAP(CMainView, CMainViewBase)
ON_WM_CREATE()
ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()

class CMainView
:public CCmdTargetEx,
public CMainViewBase,
{
lResult=CMainViewBase::OnCreate( lpCreateStruct );
}

It compiled and run ok in vs2003, but generate C4407 warning in VC++ 2005
I use /vmg, then it pass compile, but
CMainView::OnCreate does not get called when creat the window.

and I try turn off the warning without /vmg
the the OnCreate method get called
but crashed CWnd::Default()

Some online documents said can't do the multi-inhertance in MFC when using MESSAGE_MAP
but it runs ok in vs2003. Anyone knows how to get ride of this compiling/running issue
Thanks a lot!





Re: Visual C++ Language Should generate C4407 warning in VC++ 2005??

Laitu

Hi Simdoc
Have u found the solution to MFC issue
Thanks





Re: Visual C++ Language Should generate C4407 warning in VC++ 2005??

simdoc

Laitu:

It has been a while since I posted that issue and many things have changed since then. I don't really recall what we finally did but I will say that we do not use multiple inheritance with multiple MFC classes serving as bases. The multiple inheritance I had was with a non-MFC class.

That being said, maybe I can help if you tell me a little more about what you're doing. I don't understand what is CContainerView and the derivation structure you've shown. Does CCmdTargetEx derive only from CCmdTarget How about CMainViewBase, what is its derivation structure





Re: Visual C++ Language Should generate C4407 warning in VC++ 2005??

Laitu

Hi Simdoc
CCmdTargetEx is not derive from CCmdTarget.
My email is Julian.qian aattt gmail.com
Can you email to my address, I will send u the program.
Julian





Re: Visual C++ Language Should generate C4407 warning in VC++ 2005??

Laitu

Hi simdoc
Thanks for reply, it did not use multiple MFC classes serving as bases,
it just based on one MFC class.






Re: Visual C++ Language Should generate C4407 warning in VC++ 2005??

Farid_Z

Jonathan Caves - MSFT wrote:

There is a way to avoid this problem: that is to tell the compiler to be pessimistic and to not "optimize" pointers-to-members. There is a command-line switch to do this: /vmg ....
If I compile your code with this switch I don't get the warning (as the representations are now the same)

In my project about three dlls were getting C4407 warning that I was able to get rid off by using the /vmg compiler switch, however, now the application crashes ( I did not add the /vmg switch to the other dlls that were not getting the warning ). Looking in the debugger I find that the wrong member method is getting called causing some methods not to get called and that was causing the crash. My dlls use dllexport and dllimport, and I was able to compile and link successfully, but seems that all the dlls in the project must be built with /vmg switch





Re: Visual C++ Language Should generate C4407 warning in VC++ 2005??

rabbitears

I just want to report on a slightly simpler case (at least it seemed simpler to me!).

I had a set of classes in an existing hierarchy that silently performed an assortment of related functions. Then I wanted to add UI functionality to certain of them, but not all of them, using something based on CDialog. Essentially I had:

class MethodClass {...}; // ABC
class OrdinaryMethodClass : public MethodClass {...}; // slightly refined, still ABC
class SpecialMethodClass : public MethodClass {...}; // ABC
class AdvancedMethodClass : public MethodClass {...}; // ABC
class ConcreteMethodClass1 : public OrdinaryMethodClass {...};
class ConcreteMethodClass2 : public SpecialMethodClass {...};
...etc for a variety of ConcreteMethodClass<N> definitions.

I wanted to create:

class ConfigurableThing : public CDialog
{
void DoSomeUIStuffInADialog() = 0; // pure virtual => another ABC
};

with the intention of multiply inheriting to create a concrete class with UI as follows:

class ConfigurableConcreteMethodClassX : public ConfigurableThing, public ConcreteMethodClassX
{
void DoSomeUIStuffInADialog() { // whatever }
};

At first, when I had the multiple inheritance order reversed (non-MFC-derived class inherited first, then the CDialog subclass second -- bad!) I got the C4407 warnings in the message map for ConfigurableConcreteMethodClassX. When I switched the inheritance order, everything compiled without complaint, and ran like a charm. I'm using VS2005.

I couldn't find the compiler switches at first glance (/vmv /vmg etc) so goodness knows what they're set to. I declared/defined message maps in the ConfigurableThing ABC, and used DECLARE_DYNAMIC and IMPLEMENT_DYNAMIC in it as well... but have no idea if this is essential or optional

I'm happy with it so far... but if anyone wants to sound warnings before I extend this to the rest of my large class hierarchy, do speak up... :-)




Re: Visual C++ Language Should generate C4407 warning in VC++ 2005??

Kenneth Vernelen

I just want to share this experience, putting the class from which it was derived as used in the message map as first, in this case CMyMultipleDerivedClass resolved my C4407 problem related to the MESSAGE MAP for my class somehow:

class CMyMultipleDerivedClass
Stick out tongueublic CWndDerivedStuff,
public CMyOtherClasses

BEGIN_MESSAGE_MAP(CMyMultipleDerivedClass, CWndDerivedStuff)
...

END_MESSAGE_MAP()

So in your case it should be derived with CMainViewBase as the first:

class CMainView : public CMainViewBase, public CCmdTargetEx