「More C++ Idioms/多態的例外(Polymorphic Exception)」の版間の差分

削除された内容 追加された内容
編集の要約なし
1 行
=<center>Polymorphic Exception</center>=
=== Intent ===
* To create an exception object polymorphically
* To decouple a module from the concrete details of the exceptions it may throw
 
=== Also Known As ===
 
=== Motivation ===
[http://en.wikipedia.org/wiki/Dependency_inversion_principle Dependency Inversion Principle (DIP)], a popular object-oriented software design guideline states that higher level modules should not depend on lower level modules. Instead, both should depend on common abstractions (captured in the form of well-defined interfaces). For example, an object of type ''Person'' (say John) should not create and use an object of type ''HondaCivic'' but instead John should simply commit to a ''Car'' class, which is a base class of ''HondaCivic''. This allows John to upgrade to a ''Corvette'' easily in future without any changes to the class ''Person''. John can be "configured" with a concrete instance of a car (any car) using [http://en.wikipedia.org/wiki/Dependency_injection dependency injection] technique. Use of DIP leads to flexible and extensible modules that are easy to unit test. Unit testing is simplified using DIP because real objects can be easily replaced with mock objects using dependency injection.
 
However, there are several places where DIP is violated: (1) using the Singleton pattern and (2) throwing exceptions! Singleton pattern breaks DIP because it forces the use of the concrete class name while accessing the static ''instance()'' function. A singleton should be passed as a parameter while calling a function or a constructor. A similar situation arises while dealing with exceptions in C++. The ''throw'' clause in C++ requires a concrete type name (class) to raise an exception. For example,
== Solution and Sample Code ==
 
<source lang="cpp">
throw MyConcreteException("Bing Bang!");
</source>
 
Any module that throws exceptions like this immediately results into a violation of DIP. Naturally, it is harder to unit test such a module because real exception objects cannot easily be replaced with mock exception objects. A solution like the one below fails miserably as ''throw'' in C++ uses static typing and knows nothing about polymorphism.
== Known Uses ==
 
<source lang="cpp">
== Related Idioms ==
struct ExceptionBase { };
struct ExceptionDerived : ExceptionBase { };
void foo(ExceptionBase& e)
{
throw e; // Uses static type of e while rasing an exception.
}
int main (void)
{
ExceptionDerived e;
try {
foo(e);
}
catch (ExceptionDerived& e) {
// Exception raised in foo does not match this catch.
}
catch (...) {
// Exception raised in foo is caught here.
}
}
</source>
 
Polymorphic exception idiom addresses the issue.
 
=== Solution and Sample Code ===
Polymorphic exception idiom simply delegates the job of raising the exception back to the derived class using a virtual function ''raise()''
 
<source lang="cpp">
struct ExceptionBase
{
virtual void raise() { throw *this; }
virtual ~ExceptionBase() {}
};
struct ExceptionDerived : ExceptionBase
{
virtual void raise() { throw *this; }
};
void foo(ExceptionBase& e)
{
e.raise(); // Uses dynamic type of e while raising an exception.
}
int main (void)
{
ExceptionDerived e;
try {
foo(e);
}
catch (ExceptionDerived& e) {
// Exception raised in foo now matches this catch.
}
catch (...) {
// not here anymore!
}
}
</source>
 
The ''throw'' statement has been moved into virtual functions. The ''raise'' function invoked in function ''foo'' is polymorphic and selects the implementation in either ''ExceptionBase'' or ''ExceptionDerived'' class depending upon what is passed as a parameter (dependency injection). Type of ''*this'' is obviously known at compile-time, which results into raising a polymorphic exception. The structure of this idiom is very similar to that of [[More C++ Idioms/Virtual Constructor|Virtual Constructor]] idiom.
 
=== Known Uses ===
 
=== Related Idioms ===
[[More C++ Idioms/Virtual Constructor|Virtual Constructor]]
 
=== References ===
* [http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.10 How do I throw polymorphically? (parashift)]
* [http://www.cis.nctu.edu.tw/chinese/doc/research/c++/C++FAQ-English/exceptions.html#faq-17.10 How do I throw polymorphically? (NCTU)]
[[Category:{{BASEPAGENAME}}|{{SUBPAGENAME}}]]