<?xml version="1.0" encoding="GB2312" ?>
<?xml-stylesheet type="text/xsl" href="../../article.xsl" ?>

<article>

<title>Conversation after Conversation</title>

<author>晨光（Morning）</author>

<keywords>
  <keyword>C++</keyword>
  <keyword>Exception</keyword>
</keywords>

<from type="收藏"/>

<paragraph>
一段时间之前，笔者在C++ User Journal的2002年第9期上，看到了Jim Hyslop和Herb Sutter所写的Conversation系列栏目的一篇文章，题目为：Baseless Exception（没有根据的异常）。大家可以通过访问以下网址查看原文：<link href="http://www.cuj.com/experts/2009/hyslop.htm?topic=experts">http://www.cuj.com/experts/2009/hyslop.htm?topic=experts</link>。由于对文中内容存在若干疑问，笔者以mail方式请教了两位作者之一的Hyslop先生，并得到了他十分热情的帮助。现将mail内容整理并呈现给各位，我把它戏称为conversation after conversation:-）
</paragraph>

<paragraph name="Morning">
Hi Mr. Hyslop. I have a question about the first example in the article. Because the example is not completed, I modified it as follow:
<code>
#include &lt;iostream&gt;
using namespace std;

class Base
{
// ... whatever ...
};

class Derived : public Base
{
public:
	void f() {
		try {
		  throw Derived();
		}
		catch (Base &amp;) {
		  cout &lt;&lt; "Caught Base" &lt;&lt; endl;
		} catch (...) {
		  cout &lt;&lt; "Caught something else" &lt;&lt; endl;
		}
	}
};

int main(int argc, char argv[])
{
	Derived d;
	d.f();
	return 0;
}
</code>
</paragraph>

<paragraph>
To my surprise, I found the result is "Caught Base". I use the Microsoft Visual C++ 6.0 command line compiler. If I put the f() out of Derived as external function, the result is "Caught something else". I think there may be two possible reasons. First, it's a compiler compatible problem with C++ Standard(Sorry, I've not run this program in other environment because of having no other compiler on hand); Second, the program CAN get the access information for the conversion if it's a member function, and is there any clerical error on your article? What do you think about it?
</paragraph>

<paragraph name="Hyslop">
Well, at first I thought the problem was the above line - the the example in the article uses private inheritance:
<code>
class Derived : private Base
</code>
</paragraph>

<paragraph>
But after fixing it and running it through my MSVC6 compiler, it still outputs "Caught Base". Visual Studio .Net also outputs "Caught Base". On the other hand, g++ (2.95.3) gives the results predicted in the article ("Caught something else").
</paragraph>

<paragraph>
The standard is quite clear on this - a "catch (Base &amp;)" handler can only catch an exception of type Base, or of a type that is publicly and unambiguously inherited from Base. Looks like you've found a bug in MSVC.
</paragraph>

<paragraph name="Morning">
I'm sorry, there's a fault in my program. I mean the statement "class Derived : public Base". It should have been private inheritance. Thank you for testing the program with different compilers.
</paragraph>

<paragraph>
I think it's a bug, as the MSVC does not comply with the Standard. But why the Standard has such limit when there's a member function, since some compilers can get the access information for the conversion. Concerning compiler implementation, it seems that getting access information, in such case, is feasible. Now, I think I'm exactly the "apprentice" that is mentioned in your article :-(
</paragraph>

<paragraph name="Hyslop">
The problem is, the information to determine whether or not a conversion can be made is required at run-time, not at compile time. Remember that conversions can involve not only derived-to-base conversions, but also user-defined conversions, through overloaded constructors or conversion operators, such as:
<code>
class UnRelated
{
public:
   operator Base &amp;();
};

void f(Base &amp;);
void g()
{
   UnRelated un;
   f(un);
}
</code>
</paragraph>

<paragraph>
Requiring a program to store all the information about friends, public or private inheritance, conversion sequences etc. would place a 
significant burden on the program, both in memory and time. This means that run-time checking of all possible conversions is not practical.
</paragraph>

<paragraph>
At the other extreme, you clearly do not want to prohibit conversions. It seems to me the Standards Committee came up with a solution that would probably satisfy most of the real-life situations, but not impose _too_ much burden on the program.
</paragraph>

<paragraph>
Well, don't worry, I won't start referring to you as "my apprentice" ;-)
</paragraph>

<paragraph name="Morning">
Thank you for your patience. I hope I've really got the main idea of your arcticle.
</paragraph>

<paragraph>
I think the most important thing you want to emphasize is run-time conversion, not exception handling itself. Conversions from one type to another will take place not only when those two have inheritance. It seems unreasonable that the program only make run-time checking when there is a derived-to-base conversion in a member fuction(just like the bug in MSVC), while regardless of any other case. To implement the conversions in all the situations will be faced with cost of time, memory and also the complexity of program. There's a conflict between function and efficiency. The Standards Committee choose a compromise solution to deal with it.
</paragraph>

<paragraph>
Is that right?
</paragraph>

<paragraph name="Hyslop">
Yes, that's it exactly.
</paragraph>

<paragraph>
Cheers!
</paragraph>

</article>