Letters to the editor may be sent via email to [email protected], or via the postal service to Letters to the Editor, C/C++ Users Journal, 1601 W. 23rd St., Ste 200, Lawrence, KS 66046-2700.
Dear Sir,
As a subscriber to your magazine, I was astonished to read the May C/C++ Tip #6 about Making Classes Non-Derivable and could not believe what was written there. But before jumping to conclusions, I ran a minimal code example in my (Borland Builder 4) compiler guess what? My compiler does allow to derive from the class. What I had expected, of course and not because of the compiler.
class NoDeriv { protected: NoDeriv() {} }; class CannotBeDerived: private virtual NoDeriv { }; /* but derivation DOES work... */ class Test: public CannotBeDerived {};
Now either this was an Aprils fool joke (in May), or it was a test on the readers; I am rather surprised that a magazine like yours publishes this kind of stuff, and the author certainly does not deserve the CD-ROM.
Please correct me if I am wrong, otherwise my confidence in your magazine will go down quite a bit.
Alex D.
Marc,
Ive just received the May 2001 C/C++ Users Journal, and while its worth reading (good to see Carlos Moreno writing for you!), Im becoming accustomed to your C/C++ Tips being dubious.
This months is just terrible, as it claims to do something that can be done (making a class nonderivable in C++), but it fails to do it.
class final { protected: final() { } }; class nonderivable : private virtual final { // actually we can derive from this // class }; class derivative: nonderivable, virtual final { // derivative will initialize the // 'final' base object. };
(Ive checked that with Comeaus online compiler, with a gcc 3.0 pre-release, and with my own understanding of the Standard.)
We can derive from a class that has a private virtual base, by also having that same class as a virtual base. This is well known, I would have thought, and so a technical review should have picked it up. The standard idiom is to make the class nonderivable a friend of final (called PriVirFinal in the article), which naturally opens up the discussion of a templated solution which is not legal in C++:
template <class derivedclass final { friend class derived; // not legal in // C++ sadly private: final() { } }; class nonderivable : final<nonderivable> { // ... };
Maybe the C++ Standard will be changed to allow this in the future, but for now were stuck with the non-template equivalent.
Any chance of getting a correction printed, and of making sure that the C/C++ Tips are reviewed more thoroughly in future?
On a more positive note, the April Conformance Roundup was excellent; its good to see CUJ taking an active part in pushing vendors and users towards understanding the importance of conformance.
Regards,
James Dennett
[email protected]
Hi James,
Thanks for reporting this bug; yes, you are right the class can be further derived from, but the solution you propose (the template solution), as you say, is not legal in C++. But, there is yet another solution to this. Under this circumstance, I have to revert back to the original solution: using friends.
In this technique, to make both CTreeKeyError and CTreeNoItemError classes (used for exceptions) not derivable, this technique uses a lock class, to which the class that is not to be derived from is a friend. The lock class also has a private constructor, so it cannot be instantiated on its own. The actual class to be locked derives from the locking class with the public virtual access controller. Since the most derived class must initialize the virtual base, only the to-be-locked class can access the private constructor of the lock class (since this class is a friend to the lock class) to initialize it. This makes sure one cannot derive from CTreeKeyError and CTreeNoItemError classes, because the derived classes cannot initialize the virtual base. This implementation will work.
Here is the lock class:
// forward decl template <class T, class Kclass CTreeKeyError; template <class T, class K> class CTreeKeyErrorLock { friend CTreeKeyError<T, K>; private: CTreeKeyErrorLock() {} };
And heres the class to be locked:
template <class T, class K> class CTreeKeyError : public virtual CTreeKeyErrorLock <T, K> { public: CTreeKeyError(const T& t, const K& k) : m_Data(t), m_Key(k), m_strMsg ("Key already exists in binary tree.") {} void print() const { std::cout << "Data item could not be added to binary tree!" << std::endl; std::cout << "Reason: " << m_strMsg << std::endl; std::cout << "Key: " << m_Key << std::endl; std::cout << "Data: " << m_Data << std::endl; } private: const T m_Data; const K m_Key; const std::string m_strMsg; };
Hope this clarifies things; thanks for your feedback.
Cheers,
Shanker Chandrabose
As a former C++ Report subscriber (and also a current, long-time CUJ subscriber), I just wanted to let you know how much I enjoy reading (and re-reading) the C++ Experts columns now on <www.cuj.com>. Please, please, please do whatever it takes to keep them coming! And please let the columnists know that their efforts are greatly appreciated indeed!
Igor Firkusny
We are honored to host the C++ Experts on <www.cuj.com>. Glad you like them. We do too! Were confident that the C++ community will benefit from their wit and wisdom for a long time to come. cda
I just browsed through the C++ Reading List and noticed that one of the best introductory books on C++ is missing: Accelerated C++ by Andrew Koenig and Barbara E. Moo.
Maybe some of the older material can be thrown out. Now that the language and the library is standardized, it makes more sense to read books that cover Standard C++. A few older gems are still worth keeping, however, such as Copliens Advanced C++ or Lakos Large Scale C++ Software Design.
Just my $0.02.
Stefan Heinzmann
Yes, its definitely time to update the Reading List. Its been outside of my job description lately, but now that the Senior Editor position has come my way, I plan on revamping it. And Andy and Barbaras book is one of a kind, to be sure (see Francis Glassborows review of Accelerated C++ in the June 2001 issue of CUJ). Thanks for writing (and for reading!). cda
I like very much your editorial for the May 2001 issue and would have liked to mail a copy to a few of my fellow professors, but I could not find it on <www.cuj.com>. It would be nice if you could also leave the editorials on the website, it would save me doing a few photocopies.
That editorial was pretty good; too bad that it is mostly the ones that agree with the content that are going to read it.
François Gros dAillon
[email protected]
The Editors Forums are available online beginning with the January 1998 issue. Just go to the bottom of the page for whatever issue youre viewing for the link. cda
Hello,
You might have received this before. The C/C++ Tip #5, p. 41 from the CUJ January 2001 edition (a C/C++ comment macro) doesnt work with GCC, because this compiler parses out comments before macros are considered.
In general this tip is not ANSI C or ANSI C++, because the resulting comment macro is not a lexical unit of C. The Standard says that such concatenations are undefined.
I dont have a neat ANSI C replacement for Mark Timperleys solution, sorry, someone else might?
Cheers
Hugues Talbot