Path: utzoo!attcan!uunet!clyde.concordia.ca!jarvis.csri.toronto.edu!torsqnt!lethe!becker!pantor!richard From: richard@pantor.UUCP (Richard Sargent) Newsgroups: comp.lang.c++ Subject: Question for language lawyers Message-ID: <52.UUL1.3#5109@pantor.UUCP> Date: 13 Feb 90 15:00:44 GMT Organization: Pansophic Systems Inc, Graphics Product Company Lines: 163 [Note: long message (~160 lines) follows.] Earlier, I wrote asking how to handle creating a class hierarchy of display devices, for example, and to automatically create the correct derived instance depending on which display was in use. I received a number of useful answers, for which I thank their authors. They all had a common theme that you need a switch statement somewhere, usually as a standalone function, such as create_display(). The colleague for whom I asked the question took those answers and came up with the following solution. Basically, he did not like having the switch statement outside the class hierarchy. He developed this code to allow the base class to create a derived object. We have identified that there *may* a number of cases where this capability is desirable. As with any off-beat solution, it needs be used with appropriate cautions and restraint. I will entertain no flames on this particular issue. We reason that the switch logic has to be somewhere, so it might as well be with the base class, so it can be easily found and modified as new derived classes are defined. Obviously, the best situations for using this solution are when the class hierarchy is subject to very few additions, such as a hierarchy of display devices. This solution was implemented using version 1.2 of the language. It appears to be well defined with regard to any language definitions we have seen. It appears to be implementation independent. The question for the language lawyers (and author, too!) is whether this will remain a valid solution as the language evolves? Other questions include "is there a better way to have a base class create a derived class object?" and "if C++ 3.0 eliminates assignment to 'this', will the language be modified to provide a simple means to have the base class create an instance of a derived class?" ------------------------------------------------------------------------- Note: this solution is free for anyone to use in anyway they feel fit. It is in the public domain. We only ask for "credit due where credit deserved". In this case, that is "Martin Miller, Pansophic Systems, Inc.". ------------------------------------------------------------------------- Example follows: Developed using Intek C++ 1.2 and Microsoft C 5.1 under MS-DOS. For those who try this on other systems, please let me know whether this implementation works as is and/or what revisions you have to make to get it to work. If you have problems getting the desired results, I have a longer version that reports a lot of debugging information which I can mail you if you need it. I'm looking forward to all your replies! // sample showing how a BASE class constructor be used to create // DERIVED class objects #include short maketype; // simple way to determine what DERIVED class // the BASE() class constructor creates class BASE { protected: // must contain assignment to this (that is always executed) BASE( BASE *bp ) { if( this == 0 ) this = bp; } // only if an actual BASE class object was wanted public: BASE(); virtual ~BASE() {} // if wanted virtual void iam() { cout << "I am a BASE()\n"; } }; class DERIVED1 : public BASE { protected: short junk1; // must contain assignment to this (that is always executed) DERIVED1( BASE *bp ) : (bp) { this = (DERIVED1 *)bp; junk1 = 0; } public: virtual ~DERIVED1() {} // if wanted virtual void iam() { cout << "I am a DERIVED1()\n"; } }; class DERIVED2 : public BASE { protected: short junk1; short junk2; // must contain assignment to this (that is always executed) DERIVED2( BASE *bp ) : (bp) { this = (DERIVED2 *)bp; junk1 = junk2 = 0; } public: virtual ~DERIVED2() {} // if wanted virtual void iam() { cout << "I am a DERIVED2()\n"; } }; // must contain assignment to this (that is always executed) BASE::BASE() { if( this ) { // make sure it's NOT a static or auto variable cout << "error: BASE class objects must be dynamically allocated\n"; exit(1); } switch( maketype ) { case 0: this = (BASE *)new char[sizeof(BASE)]; new BASE(this); break; case 1: this = (BASE *)new char[sizeof(DERIVED1)]; new DERIVED1(this); break; case 2: this = (BASE *)new char[sizeof(DERIVED2)]; new DERIVED2(this); break; } } main() { maketype = 0; BASE *bp0 = new BASE; bp0->iam(); delete bp0; cout << "\n"; maketype = 1; BASE *bp1 = new BASE; bp1->iam(); delete bp1; cout << "\n"; maketype = 2; BASE *bp2 = new BASE; bp2->iam(); delete bp2; } -------------------------------------------------------------------------- Note: the use of the global "maketype" is only one of many possible mechanisms to identify which derived class should be made. In the example of a display device hierarchy, the base class would include an "identify_display()" funtion. -------------------------------------------------------------------------- This program should produce the following results: I am a BASE() I am a DERIVED1() I am a DERIVED2() -------------------------------------------------------------------------- Richard Sargent Internet: richard@pantor.UUCP Systems Analyst UUCP: ...!mnetor!becker!pantor!richard