Letters to the editor may be sent via email to cujed@mfi.com, or via the postal service to Letters to the Editor, C/C++ Users Journal, 1601 W. 23rd St., Ste 200, Lawrence, KS 66046-2700.
CUJ,
The attached ASCII file is a comment on your response to Kyle York's mail in the August CUJ:
"Your reply to Kyle York in the August issue was a bit off the mark.
"Consider the processing of Windows messages. Suppose you have defined classes A, B, and C such that class C is derived from class B which is derived from class A and class A defines the virtual function Process, which takes a window message as an argument. Further, suppose that class B and class C also define the same virtual function. When the Process function is called, class C will get control first. If the message is not one that it acts upon then class C will call the class B version of the function using the notation B::Process. Likewise, B may pass the call on to a using the notation A::Process.
"Now, suppose that it becomes necessary to change the definitions so that class C is derived from class B2 which is derived from B, etc. Now you must change every instance in class C of B::Process or B2::Process will be by-passed. What Kyle wants -- me too -- is for there to be a notation we can use in C::Process that will tell the compiler to call the container class's Process. Something like :::Process(...); so that when class C is derived from B, B::Process is called, and when class C is derived from B2, B2::Process is called. No 'special access privileges' needed! Class C is simply passing its call up the chain.''
Now for my two cents. I would like to see something added to templates. If you have a template class defined as follows:
template <class X> class A { public: // ... static void Foo1(A*); void Foo3(void); };I would like for class A to be an implied base class of class A<T> so that procedures independent of the template arguments can be implemented at the implied base class level. This would allow
void A::Foo1(A*) {for (int i=0;i<5;i++); /* can't be inline*/}to be written in a compilation unit and shared among all instances of class A.
A related desire is to have a mechanism which will force the compiler to create specific instances of the templated procedure. Using the previously defined class A and its procedures, one might like to implement it as
template <class X> void A<X>::Foo3(void) {X x;for (int i=0; i<24;i++) x++;}but the code must be visible to one and only one compilation unit that uses it and to no other. Otherwise, you get either an undefined function error or a duplicate function error from the linker. What would solve the problem is if you could add code such as
void A<int>::Foo3(void) = 0; void A<float>::Foo3(void) = 0;to a compilation unit. This would tell the compiler to create int and float versions of the template function A::Foo3. Use of
A<long> a; a->Foo3();would still result in a linkage error unless a routine was written for it.
I confess that my desire for the second mechanism is much stronger than the first because you can get around it by defining a base class and using it like this:
class ABASE { public: static void Foo1(ABASE *); }; template <class X> class A : public ABASE { public: // ... };The problem with the workaround is that it adds an extra byte that might be avoided with an implied base class. I understand that template classes are already difficult for the compiler to handle and the special processing necessary for handling a zero-size base and virtual function might be too much to ask. But, I've always found it best to ask since others may find it as useful if not more so.
Thanks,
Greg Brewer
Hi,
In the August 1996 letters section, Kyle York asked for an "immediate ancestor'' operator. The answer to his letter assumed that he wanted to access the internals of an ancestor class, but I believe all he really wanted was to avoid hard-coding the name of the ancestor class in his code. E.g., he wants to be able to say inherited::Func() instead of HardCodedParentClassName::Func(), the latter being less expressive of intent and more brittle in the face of change. This is an entirely reasonable request and, as documented in Stroustrup's D&E (p. 90) might even have been added to the language, except that someone pointed out that you can just do this:
class Derived : public Base { public: typedef Base inherited; virtual int OverRide() { inherited::OverRide(); // additional stuff } };It's not quite as convenient as a new keyword (you have to add the typedef yourself to each such class, and change it if the name of the base class changes), but it's a serviceable solution, and was enough to keep inherited:: out of the standard (so far anyway -- the ANSI C++ fat lady clears her throat a lot, but ain't made a melody yet).
Ron Burk
Windows Developer's Journal
Dear Mr. Plauger,
I guess you were half asleep when you answered the question from Kyle York in the August '96 edition of CUJ. It is clear from the question that Kyle was aksing about super/sub-class relationships but your answer clearly assumes nested class definitions.
I, too, have sometimes wished that C++ had a keyword such as Java's super, meaning the immediate superclass of the current class. Of course, Java only has single inheritance but a compiler could surely resolve any ambiguity with the normal techniques of type matching. The reason why we would want such a capability is described in Kyle's letter. Frequently one uses inheritance to obtain a default implementation for a class, overriding those members for which non-default behavior is required.
If one subsequently changes the implementation by using a different base class then one has to go through all overridden functions to check for references to the old implementation. Of course, the compiler will normally flag them but it is still a chore.
A simple keyword would also help in those cases where a class is derived from an instantiation of a template. The "name'' of the parent class can become quite complex, involving as it does a repeat of all the instantation parameters. Once again, change any parameter and you've got to locate any references in methods in the derived class and fix them up.
Thanks for a great magazine and an interesting column.
Steve Wheeler
Dear Mr. Plauger,
I just read the letter from Kyle York, concerning the proposal of a "immediate ancestor operator,'' in the August issue of CUJ and your answer. To my opinion there is a little misunderstanding: I think, what Kyle means is kind of an operator (which he proposes might be spelled ..) that delivers a reference to the superclass -- the one from which the actual one is inherited, but not embedded.
This kind of operator could be resolved at compile time to A::foo(), in his example. There is in fact such a mechanism in Smalltalk, called super. When you reference a normal member of an object (they call it message...), you just say (if xxx was the member) self xxx.
If you want to access the version of the member provided by the superclass, you say super xxx.
I agree with Kyle that such a mechanism would be handy, because you don't have to specify the actual name of the class, from which you inherited, and as Kyle stated, it would be easier to change the inheritance. In the last big software project I was working on, I stumbled a few times over this kind of error. After having changed the name of my superclass (actually having inserted a new class in between the actual class and the old superclass), I forgot to correct every occurence of
oldsuperclass::xxx to superclass::xxxThis is dangerous, as the compiler doesn't complain about it if oldsuperclass::xxx is still reachable from my member function. I hope I could clarify Kyle's point and wish you can keep up your good job! I really appreciate reading your paper!
Harald Nowak
ishn@infrasoft.co.at
Dear pjp,
I'm writing this as a response to the letter by Kyle York in the August edition of The C/C++ User's Journal. What Mr. York is referring to isn't the problem of a member class accessing members of its containing class -- he's addressing a problem tackled by Mr. strdup() in The C++ Programming Language, 2nd Ed. in section 6.5.2, "Ambiguity Resolution.'' The trick Mr. Stroustrup provides is to add a special typedef in every class. I'm quoting his example here:
class employee { // ... virtual void print(); } class foreman : public employee { typedef employee inherited; // ... void print(); } class manager : public foreman { typedef foreman inherited; // ... void print(); }As described earlier in the section, the class hierarchy originally consisted only of employee and manager, then foreman was added. Without the typedef inherited, the definition of manager::print() was like this:
void manager::print ( void ) { employee::print(); // ... }If class foreman is inserted into the hierarchy, manager::print() should call foreman::print(), but unless you do a search-and-replace in the source code, it won't do so. Changing the code to void manager::print ( void )
{ inherited::print(); // ... }eliminates the problem, allowing simple insertion of a new class into the inheritance tree.
Yours sincerely,
Hermann SeibSomething tells me I missed the point of Mr. York's letter. Every once in a while, my mind simply goes walkabout, and this is one of those times. Thanks to all who wrote in to set the record straight. We've reprinted most of the letters received to date, largely unabbreviated, to show the variety of viewpoints on this topic. I think the responses cover the subject well. -- pjp
Editor,
Subject: June issure of CUJ
This issue rocked my boat. I couldn't get enough. I wish more authors would write about their experiences. I am sure there is a multitude of "inventions'' out there being lost to obscurity. Thank you for producing such a good issue. Please get Stephen Schulist to write more articles.
Danny Rubis
Noted, thanks. -- pjp
CUJ,
This is in response to the August 1996 article entitled "Approximate Inverse Color Mapping" by Tim Kientzle. Every color mapping routine that I have come across, uses as the color distance function something to the effect of 4*(deltaGreen)2 + 3*(deltaRed)2 + 2*(deltaBlue)2 in order to properly adjust for human visual perceptions. Not only did the article's function use a linear and non-weighted algorithm for determining the distance between two colors, Tim incorrectly states in the fourth paragraph "...human eyesight is more sensitive to variations in red than in green..." Human eyesight is more sensitive to green, than red then blue. This is how all color mapping algorithms perform their calculations.
It would seem that additional justfication should be included with the article or that it should be omitted. It seems it is blatantly wrong.
Hal Tolley
Tim Kientzle replies:
Hal,
Thanks for your feedback. You're quite correct that I swapped "red" and "green" in the article, both in the phrase you quoted and in the source code. Mea culpa. As for weighting, this technique places the most significant color two bits further to the left than the least significant color, an effective weighting of 4:2:1. However, you must keep in mind that this is an approximate algorithm; it does not claim to always find the actual closest color. I find it interesting primarily because it is both fast--there are no squares to compute--and memory efficient. In comparison, brute-force searches are exact and memory efficient but slow, while inverse lookup tables are fast and nearly exact, but require much more memory.
Tim Kientzle
Editor,
I don't know if I'm sending this to the right place, but here goes... I have just recently become aware that polymorphism seems to be impossible in constructors. For example, take the following:
#include <stdio.h> class Base{ public: Base() {Print();}; protected: virtual void Print() {printf("Base\n");}; } class Child{ public: Child():Base() {}; protected: virtual void Print() {printf("Child\n");}; }If you create an instance of Child, you will see the message "Base" on the screen, not "Child" as I expected. Apparently, the reason for this is that the virtual method tables are initialized in the constructor, and constructors for Base classes are called first. The result of this is that Base's constructor is called before Child's, and that means that the call to Print is bound using Base's virtual method table instead of Child's because Child's hasn't been built yet.
What's worse, in the application I was writing, the virtual function in question was abstract, so I got a "call to abstract function" message on my screen!
A couple of questions: 1) Do I understand this correctly? and 2) Is there any way to get polymorphism in a constructor?
Thanks.
Patrick Doyle
It is always a tough design decision, in any programming language with inheritance and polymorphism, to decide just where an object changes from being of base to derived type. One technique for avoiding such gray areas is to introduce an explicit Init member, and to use only trivial constructors. Then you do all the nontrivial work only after the dynamic type of an object is well established. -- pjp
Dear CUJ,
For the last two month I've been reading your journal with increasing interest. I really like the way Bobby Schmidt writes his articles (especially when including footnotes like #[1] of his C->C++ Mutations, Part 1).
I usually write programs with Microsoft Foundation Classes. I know that you are planning an article about Windows programming, but I would like your magazine even more if you included one little article about Windows programming in, let's say, every other issue.
Normally I would offer you an article concerning that subject, but I can't keep up with the knowledge of Bobby and the others.
Sascha Herpers
a2871840@athena.rrz.uni-koeln.deA lot of us have trouble keeping up with Bobby, particularly with his puns. -- pjp