1. Trang chủ
  2. » Công Nghệ Thông Tin

HandBooks Professional Java-C-Scrip-SQL part 45 ppt

6 55 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 6
Dung lượng 21,39 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

dynamic_cast tHRows an exceptionstd::bad_castif the conversion is not possible when used on a reference type.. There is no such thing as a null reference in C++, so either the conversion

Trang 1

polymorphic_cast

Header: "boost/cast.hpp"

Polymorphic conversions in C++ are performed via dynamic_cast A feature of dynamic_cast, which is sometimes also the cause of erroneous code, is that it

behaves differently depending on the type with which it is used dynamic_cast tHRows an exceptionstd::bad_castif the conversion is not possible when used on a reference type The reason for the exception is simple There is no such thing as a null reference in C++, so either the conversion succeeds and the result is a valid reference or it fails and you get an exception instead Of course, when using

dynamic_cast to convert a pointer type, failure is indicated by returning the null pointer

dynamic_cast's different behavior depending on whether pointer or reference types are used is a valuable property, because it allows the programmer to express intent Typically, if a failed conversion doesn't constitute a logical error, the pointer

conversion is used, and if it is an error, the reference version is used

Unfortunately, the difference is quite subtleit boils down to an asterisk or an

ampersandand it isn't always a natural choice What if a failed cast to a pointer type

is an error? To make that clear by having an exception thrown automatically, and

to make the code consistent, Boost offers polymorphic_cast It always throws a std::bad_cast exception if the conversion fails

In The C++ Programming Language 3rd Edition, Stroustrup has the following to say about dynamic_cast with pointer types, and the fact that it can return the null pointer:

"Explicit tests against 0 can beand therefore occasionally will beaccidentally

omitted If that worries you, you can write a conversion function that throws an exception in case of failure."

polymorphic_cast is precisely that conversion function

Usage

polymorphic_cast is used just like dynamic_cast, except (pun intended) that it always throws a std::bad_cast on failure to convert Another feature of

polymorphic_cast is that it is a function, and can be overloaded, if necessary As a natural extension to our C++ vocabulary, it makes code clearer and casts less error

Trang 2

prone To use it, include the header "boost/cast.hpp" The function is parameterized

on the type to convert to, and accepts one argument to be converted

template <class Target, class Source>

polymorphic_cast(Source* p);

It should be mentioned that there is no version of polymorphic_cast for reference types The reason for this is that the implementation would do exactly what

dynamic_cast already does, and there is no need for polymorphic_cast to duplicate existing functionality of the C++ language The following example shows the syntactic similarity with dynamic_cast

Downcast and Crosscast

There are two typical scenarios when using dynamic_cast or polymorphic_cast is appropriate: when downcasting from a base class to a derived class or when

crosscasting, which means casting from one base class to another The following example shows both types of casts using polymorphic_cast There are two base classes, base1 and base2, and a class derived that inherits publicly from both of the base classes

#include <iostream>

#include <string>

#include "boost/cast.hpp"

class base1 {

public:

virtual void print() {

std::cout << "base1::print()\n";

}

virtual ~base1() {}

};

class base2 {

public:

void only_base2() {

std::cout << "only_base2()\n";

}

virtual ~base2() {}

};

class derived : public base1, public base2 {

public:

Trang 3

void print() {

std::cout << "derived::print()\n";

}

void only_here() {

std::cout << "derived::only_here()\n";

}

void only_base2() {

std::cout << "Oops, here too!\n";

}

};

int main() {

base1* p1=new derived;

p1->print();

try {

derived* pD=boost::polymorphic_cast<derived*>(p1);

pD->only_here();

pD->only_base2();

base2* pB=boost::polymorphic_cast<base2*>(p1);

pB->only_base2();

}

catch(std::bad_cast& e) {

std::cout << e.what() << '\n';

}

delete p1;

}

To show how polymorphic_cast works, the first thing we did was to create an instance of derived and manipulate it through various pointers to the base and derived classes The one function that will work out-of-the-box for p1 is print, which is a virtual function in base1 and derived We then use a downcast to be able

to call only_here, available only in derived:

derived* pD=boost::polymorphic_cast<derived*>(p1);

pD->only_here();

Note that if the polymorphic_cast fails, a std::bad_cast exception is thrown, so the code is protected by a try/catch block This behavior is exactly the same as for dynamic_cast using reference types The pointer pD is then used to call the

function only_base2 The function is a non-virtual function in base2, but is also provided by derived, which hides the version in base2 Thus, we need to perform a

Trang 4

crosscast to get a pointer to base2 to call base2::only_base2 rather than

derived::only_base2

base2* pB=boost::polymorphic_cast<base2*>(p1);

pB->only_base2();

Again, if the conversion fails, an exception is thrown This example shows the ease with which error handling is performed when using polymorphic_cast if failed conversions are considered errors There is no need to test for null pointers or to propagate an error out of the function explicitly As we shall see shortly,

even lead to undefined behavior

dynamic_cast Versus polymorphic_cast

To see the difference between these complementary casts,[3] let's put them head to head in a race against complexity We'll reuse the classes base1, base2, and derived from the previous example You'll note that the tests for a valid pointer when

employing dynamic_cast on pointer types are both tedious and repetitious, which makes the tests unfortunate candidates for being omitted by stressed programmers [3]

Technically, dynamic_cast is a cast operator, whereas polymorphic_cast is a function template

void polymorphic_cast_example(base1* p) {

derived* pD=boost::polymorphic_cast<derived*>(p);

pD->print();

base2* pB=boost::polymorphic_cast<base2*>(p);

pB->only_base2();

}

void dynamic_cast_example(base1* p) {

derived* pD=dynamic_cast<derived*>(p);

if (!pD)

throw std::bad_cast();

pD->print();

base2* pB=dynamic_cast<base2*>(p);

if (!pB)

throw std::bad_cast();

pB->only_base2();

}

Trang 5

int main() {

base1* p=new derived;

try {

polymorphic_cast_example(p);

dynamic_cast_example(p);

}

catch(std::bad_cast& e) {

std::cout << e.what() << '\n';

}

delete p;

}

The two functions, polymorphic_cast_example and dynamic_cast_example,

perform exactly the same work but in different ways The difference is that

wherever a dynamic_cast involving pointers is performed, we must remember to test the returned pointer to see if it is null In our example, this designates an error, which should result in an exception of type bad_cast being thrown.[4] When using polymorphic_cast, the error handling is localized to the exception handler for

std::bad_cast, which means that we do not need to worry about testing any returned values from casting between types In this trivial example, it's not that hard to remember to test for validity of the returned pointer, but it still requires more work than when using polymorphic_cast Add a couple of hundred lines of code, and two or three programmers performing maintenance in the function, and the risk of

a forgotten test, or failure to throw the appropriate exception, increases drastically [4]

Of course, the returned pointer must always be tested anyway, unless one is absolutely certain that the conversion will not fail

polymorphic_cast Isn't Always the Right Choice

If a failed polymorphic pointer cast is not an error, you should use dynamic_cast rather than polymorphic_cast For example, this is often the case when one uses dynamic_cast to test for certain types Using exception handling to try conversions

to several types makes for inefficient, hard-to-read code It is this behavior of

dynamic_cast that is its real strength When using both polymorphic_cast and dynamic_cast, you can capture your intent very clearly Even without

polymorphic_cast, if people know about the different ways that dynamic_cast works, it is still possible to achieve the same level of safety, as is shown in the following example

Ngày đăng: 06/07/2014, 03:20