duplicated member variables in derived classes
-
I expect those will soon be Microsoft extensions to XML.
Actually this is not XML, this an extension to plain English. :)
-
Consider the following simple Win32 console app. It defines 3 classes A, B, and C. The classes B and C derive from class A. We create a CArray of class A pointers. Since B and C are derived from A, we can add pointers to B and C to the CArray. On the lines with "LINE A", "LINE B", and "LINE C" comments, what would the value of pA->myType be in each case? Hint, it won't be TYPEA, TYPEB, or TYPEC! To test this app, set breakpoints at each of the 3 lines with the calls to GetAt, and view the value of pA->myType in the debugger.
// FooTest.cpp : Defines the entry point for the console application.
//#include "stdafx.h"
#include "FooTest.h"
#include <afxtempl.h>#ifdef _DEBUG
#define new DEBUG_NEW
#endif// The one and only application object
CWinApp theApp;
using namespace std;
enum TClassType {TYPEA, TYPEB, TYPEC};
class A
{
public:
A() {};
~A();
TClassType myType;
};class B : public A
{
public:
B() { myType = TYPEB; }
~B();
TClassType myType;
};class C : public A
{
public:
C() { myType = TYPEC; }
~C();
TClassType myType;
};int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
CArray<A*> myArray;
A* pA;myArray.Add(new A); myArray.Add(new B); myArray.Add(new C); pA = myArray.GetAt(0); //LINE A pA = myArray.GetAt(1); //LINE B pA = myArray.GetAt(2); //LINE C // initialize MFC and print and error on failure if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0)) { // TODO: change error code to suit your needs \_tprintf(\_T("Fatal Error: MFC initialization failed\\n")); nRetCode = 1; } else { // TODO: code your application's behavior here. } return nRetCode;
}
The value-of pA->myType is the value-of pA->A::myType which has not been initialized. Some changes: class A {public: A(){/*myType = TYPEA;*/} ~A(){} TClassType myType;}; class B : public A {public: B(){ myType = TYPEB; } ~B(){} TClassType myType;}; class C : public A {public: C(){ myType = TYPEC; } ~C(){} int myType;}; A* pA; B* pB; C* pC; pA = myArray.GetAt(0); //LINE A pA = myArray.GetAt(1); //LINE B pB = (B*)pA; TClassType eAB = pB->myType; TClassType eAA = pB->A::myType; pA = myArray.GetAt(2); //LINE C pC = (C*)pA; TClassType eAC = TClassType)pC->myType; eAA = pC->A::myType; Results: TYPEB == pB->myType // B::myType 2 == pC->myType // C::myType, 2==TYPEC ? == pA->myType // A::myType when uninitialized TYPEA == pA->myType // A::myType when initializion is uncommented Comments: Data-members are hidden or overridden. "Plain" function-members are hidden or overridden. Virtual function-members are virtual (behavior you expected). Hiding/overriding depends on NAME not type (see TClassType versus int). More comments: Such hiding is probably most often not done on purpose. Therefore Hiding data-members is 99.9999% (sure to result in) a bug. Hiding function-members is 99% a bug.