View
220
Download
1
Embed Size (px)
Citation preview
RTTI – why?
Problem: Up-casting works fine.
Treating sub-class as base classShape * s = new Circle();
What about down-casting? might not be safe ! correctness cannot be determined
by the compiler.Circle * c = (Circle*) s;
Shape
Line Circle
RTTI
RTTI – Run Time Type Information
Mechanisms for RTTI:
1. dynamic_cast operator
2. typeid operator (and type_info class)
The ‘dynamic_cast‘ operator
dynamic_cast<T>(expression)
Enables run-time type checking: returns a valid pointer if “expression” is
of type “T” NULL otherwise
Cast of a reference type throws an exception when it fails (“bad_cast”)
Dynamic_cast : example
Shape* s = container.pop();
Circle* c = dynamic_cast<Circle*>(s);
if ( c != NULL ) { // c is a circle
c->doSomething();
else
handle(); //handle unexpected event
Note: the actual type of “s” is not mentioned! Can be any sub-class of Circle.
Dynamic_cast : example
Shape s; Circle c;
Line l; ThinLine tl;
Shape* arr[4] = {&s, &c, &l, &tl};
for ( int i=0; i<3; i++ ) {
Line * pl = dynamic_cast<Line*>( arr[i] );
pc == NULL? cout << “cast ok\n” :
cout << “cast fail\n”;
}
Shape
LineCircle
Output:
cast fail // Shape to Line
cast fail // Circle to Line
cast ok // Line to Line
cast ok // ThickLine to Line
ThickLine
dynamic_cast - more
dynamic_cast<T>(expression)
Note: Used only on pointer or reference types. Can be used for up-cast, down-cast
and also for cross-cast (out of this scope) Only for types with virtual-functions
(“Polymorphic types”) These object have a space for the information
about the type: the virtual function table
dyn_cast: only for polymorphics
void foo(Shape * s, Time * t) {
Circle * c = dynamic_cast<Circle*>( s ); //ok
Date * date = dynamic_cast<Date*>( t ); //error
}
class Circle : public Shape {virtual void draw();…
}
class Date : public Time {… // Time has no virtual functions
}
RTTI : typeid operator• Obtains info about an object/expression
• usage: typeid( obj ) (like “sizeof”)
Example:
Dog d;Cat c;cout << “d is a “ << typeid(d).name() << “,”
<< “c is a “ << typeid(c).name() <<endl;
Output: d is a Dog, c is a Cat
type_info class• typeid(expression) returns an object of the type_info class.
• e.g. type_info& ti = typeid(d);class type_info {
public:
bool operator==( type_info const&)const;
char const* name() const;
…
private:
type_info( type_info const&); //prevent copying
type_info& operator=( type_info const& );
}
RTTI misusevoid rotate( shape const& s ) {
if (typeid(s) == typeid(Circle) )
//do nothing
else if (typeid(s) == typeid(Triangle) )
//rotate Triangle
else if (typeid(s) == typeid(Rectangle) )
//rotate Rectangle
…
}
• Use virtual functions (i.e. polymorphism) when you can !•VERY common misuse of RTTI
Leading example: image files
Images are stored as matrices of numbers (Pixels).
Here, we deal with gray-scale images (“black and white”)
8 bits per pixel i.e. each pixel between 0 and 255
0 is white, 255 is black, others are gray
255
0
0
255
0
100
storing images
How can we store images on files? For each image we want to store:
width //integer height //integer number of bits per pixel //short the pixels //matrix of integers
Requirements: read/write easily, save space, save computation, etc.
storing imagesFirst try: text files (like you did so far)
width = 3
height = 2
bits_per_pixel = 8
255, 0, 0
0, 255, 100
“myImg.txt”
cons: long needs parsing (e.g.
atoi for numbers)
pros: readable by humans
easy to edit but who handles
images like that?
Binary filesBetter solution: Binary files
Save the data the way the computer holds it
pros: Smaller No parsing (faster)
Widely used ! For example: BMP files, other data
cons: hard to read for
humans Machine
dependant
Images as binary files
3
2
8 255
0 0
0 255
100
pixel1 byte[1,1,1,1,1,1,1,1]
pixel1 byte[0,0,0,0,0,0,0,0]
Example: writing a binary filePixel pixs[30];
int width = 100, height = 150;
short bitsPerPix = 16;binary
open for writing
ofstream outfile;
outfile.open(“pic.raw", ios::bin | ios::out);
outfile.write(&width, sizeof(int));
outfile.write(&height, sizeof(int));
outfile.write(&bitsPerPix, sizeof(short));
outfile.write(pixs, 30*sizeof(Pixel));
outfile.close();
ostream& write( char const* str, streamsize n);
c++ style casting
At the beginning c++ supported two styles of casts: (typename)expression typename(expression)
Instead there are now four new casting operators: static_cast<type>(expression) const_cast<type>(expression) reinterpret_cast<type>(expression) dynamic_cast<type>(expression)
The 'static_cast'operator
Works where implicit conversion exists standard or user-defined conversion up-casts
Safer that “old-style” casts e.g. won’t cast int* to float*
Failure causes a compiler error No dynamic checking is done!
int i = static_cast<int>(12.45);
static_cast<type>(expression)
The ‘const_cast'operator
Is used to remove (or add) const-ness:void g(C * cp);
void f(C const* cp) {g(const_cast<C *>(cp));
} Usually, you should design your
variables/methods such that you won’t have to use const_cast.
Failure causes compiler errors
const_cast<type>(expression)