260 likes | 458 Views
Plab – Tirgul 11 RTTI, Binary files. RTTI – why?. Shape. Problem: Up-casting works fine. Treating sub-class as base class Shape * s = new Circle(); What about down-casting ? might not be safe ! correctness cannot be determined by the compiler. Circle * c = (Circle*) s;. Line. Circle.
E N D
RTTI – why? Shape Problem: • Up-casting works fine. • Treating sub-class as base class Shape * s = new Circle(); • What about down-casting? • might not be safe ! • correctness cannot be determined by the compiler. Circle * c = (Circle*) s; Line Circle
RTTI RTTI – Run Time Type Information Mechanisms for RTTI: • dynamic_cast operator • 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 Note: the actual type of “s” is not mentioned! • Can be any sub-class of Circle. Shape* s = container.pop(); Circle* c = dynamic_cast<Circle*>(s); if ( c != NULL ) { // c is a circle c->doSomething(); else handle(); //handle unexpected event
Dynamic_cast : example Shape Circle Line 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”; } ThickLine Output: cast fail // Shape to Line cast fail // Circle to Line cast ok // Line to Line cast ok // ThickLine to Line
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 class Date : public Time { … // Time has no virtual functions } 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();… }
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 misuse void 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 0 255 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 images First try:text files (like you did so far) cons: • long • needs parsing (e.g. atoi for numbers) pros: • readable by humans • easy to edit • but who handles images like that? “myImg.txt” width = 3 height = 2 bits_per_pixel = 8 255, 0, 0 0, 255, 100
Binary files Better 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 width 2 bytes [0,…,0,0,1,1] 3 2 8 255 height 2 bytes [0,…,0,0,1,0] 0 0 0 255 100
Images as binary files 3 2 8 255 bits per pixel 1 byte [0,0,0,0,1,0,0,0] 0 0 0 255 100
Images as binary files pixel 1 byte [1,1,1,1,1,1,1,1] 3 2 8 255 0 0 pixel 1 byte [0,0,0,0,0,0,0,0] 0 255 100
Binary files 3 2 16 255 bits per pixel now value 16 0 0 255 0 0
open for writing binary 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(); Example: writing a binary file Pixel pixs[30]; int width = 100, height = 150; short bitsPerPix = 16; ostream& write( char const* str, streamsize n);
Learn by yourselves:c++ casting(see slides ahead andStroustrup 15.4 and more) .
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 static_cast<type>(expression) • 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);
The ‘const_cast'operator const_cast<type>(expression) • 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
‘reinterpret_cast'operator reinterpret_cast<type>(expression) • Is used to reinterpret byte patterns. double d(10.2); char* dBytes = reinterpret_cast<char *>(&d); • Circumvents the type checking of c++. • Very implementation-dependent. • Rarely used. • Very dangerous !