Saturday, May 2, 2015

1. C-stype casting
Casting trong C có dạng như dưới đã được đề cập tại đây.

  (new_type) expression  
Trong đó new_type kiểu mà expression phải được chuyển đổi thành.

2. C++ Casting
Việc casting trong C++ được thực hiện thông qua các toán tử sau:
 reinterpret_cast <new_type> (expression)  
     dynamic_cast <new_type> (expression)  
      static_cast <new_type> (expression)  
       const_cast <new_type> (expression)  


+ static_cast: chuyển kiểu dữ liệu bình thường như int -> char, giữa các lớp kế thừa.
+ dynamic_cast: chuyển đổi kiểu con trỏ giữa các lớp đa hình trong đa kế thừa.
+ reinterpret_cast: chuyển đổi giữa 2 kiểu dữ liệu ko có mối liên hệ, vd như là int -> pointer,...
+ const_cast: bỏ const ra khỏi dữ liệu được chuyển đổi.

Một vài khái niệm:
+ upcastconverting pointer-to-derived to pointer-to-base
+ downcastconverting from pointer-to-base to pointer-to-derived

Trong kế thừa upcast được thực hiện hợp lệ mà không cần toán tử casting
 class Base { };  
 class Derived: public Base { };  
 Base * base = new Derived;  

2.1 static_cast
static_cast làm việc tương tự như cast trong C
 float d=3.14159265;  
 int i = static_cast(d);  //the same  as (int)d in C  
Khi viết code C++ nên dùng static_cast thay vì dùng dạng cast thông thường như trong C.

Xét ví dụ downcast :
static_cast.cpp
 #include <iostream>  
 #include <stdio.h>   /* printf, scanf, puts, NULL */  
 #include <stdlib.h>   /* srand, rand */  
 #include <time.h>    /* time */  
   
   
 using namespace std;  
   
 class Base  
 {  
 public:  
   virtual void DoIt() = 0; // pure virtual  
   virtual ~Base() {}  
 };  
   
 class Foo : public Base  
 {  
 public:  
   virtual void DoIt() { cout << "Foo \n"; }  
   void FooIt() { cout << "Fooing It... \n"; }  
 };  
   
 class Bar : public Base  
 {  
 public :  
   virtual void DoIt() { cout << "Bar \n"; }  
   void BarIt() { cout << "baring It... \n"; }  
 };  
   
 Base* CreateRandom()  
 {  
   if( (rand()%2) == 0 )  
     return new Foo;  
   else  
     return new Bar;  
 }  
   
 int main()  
 {  
   for( int n = 0; n < 5; ++n )  
   {  
     Base* base = CreateRandom();  
   
     base->DoIt();  
   
     Bar* bar = static_cast<Bar*>(base);  
     Foo* foo = static_cast<Foo*>(base);  
     if( bar )  
       bar->BarIt();  
     if( foo )  
       foo->FooIt();  
     delete base;  
     base = NULL;  
   
     printf("-------------STATIC_CAST-------------- \n");  
   }  
   
   return 0;  
 }  
   

Compile & Execute
 $ g++ static_cast.cpp   
 $ ./a.out   
 Bar   
 baring It...   
 Fooing It...   
 -------------STATIC_CAST--------------   
 Foo   
 baring It...   
 Fooing It...   
 -------------STATIC_CAST--------------   
 Bar   
 baring It...   
 Fooing It...   
 -------------STATIC_CAST--------------   
 Bar   
 baring It...   
 Fooing It...   
 -------------STATIC_CAST--------------   
 Bar   
 baring It...   
 Fooing It...   
 -------------STATIC_CAST--------------    

Kết quả cho thấy khi baseBar thì vẫn cast thành Foo được, và khi base là Foo thì vẫn cast thành Bar được, điều này xét về logic là không đúng.
Note: Chính vì vậy static_cast chỉ nên dùng khi ta biết chắc chắn kiểu dữ liệu được cast là hợp lệ.

 Base* base = new Bar;  
 Bar* bar = static_cast<Bar*>(base);   
 // OR   
 Base* base = new Foo;  
 Foo* foo = static_cast<Foo*>(base);  

2.2 dynamic_cast
Xét ví dụ như trên nhưng hàm main viết lại như dưới
dynamic_cast.cpp
 int main()  
 {  
   
   for( int n = 0; n < 10; ++n )  
   {  
     Base* base = CreateRandom();  
   
     base->DoIt();  
   
     Bar* bar = dynamic_cast<Bar*>(base);  
     Foo* foo = dynamic_cast<Foo*>(base);  
     if( bar )  
       bar->BarIt();  
     if( foo )  
       foo->FooIt();  
     delete base;  
     base = NULL;  
   
     printf("-------------DYNAMIC_CAST-------------- \n");  
   }  
   return 0;  
   
 }  

Compile & Execute:
 $ g++ dynamic_cast.cpp   
 $ ./a.out   
 Bar   
 baring It...   
 -------------DYNAMIC_CAST--------------   
 Foo   
 Fooing It...   
 -------------DYNAMIC_CAST--------------   
 Bar   
 baring It...   
 -------------DYNAMIC_CAST--------------   
 Bar   
 baring It...   
 -------------DYNAMIC_CAST--------------   
 Bar   
 baring It...   
 -------------DYNAMIC_CAST--------------   

Kết quả cho thấy khi base là Bar thì không thể cast thành Foo, và khi base là Foo thì không thể cast thành Bar được, đây là điểm khác so với static_cast.
Note: dynamic_cast thực hiện công việc kiểm tra kiểu dữ liệu cast để có được kết quả đúng, chính vì vậy phù hợp với bài toán khi ta không biết chắc chắn (random) sẽ base sẽ downcast về derived nào. Đặc tính Run-Time Type Information (RTTI) trong một số compiler bị disable vì thế phải chắc chắn nó được enable khi sử dụng dynamic_cast.

2.3 reinterpret_cast
reinterpret_cast thực hiện chuyển đổi các kiểu dữ liệu không liên quan gì đến nhau, việc cast cũng không có kiểm tra như trong static_cast, nó thường được dùng để cast các function pointer.

 class A { /* ... */ };  
 class B { /* ... */ };  
 A * a = new A;  
 B * b = reinterpret_cast<B*>(a);  

 int a = 0xffe38024;  
 int* b = reinterpret_cast<int*>(a);  

2.4 const_cast
Thực hiện việc bỏ const ra khỏi dữ liệu được chuyển đổi

Ex
const_cast.cpp
 // const_cast  
 #include <iostream>  
 using namespace std;  
   
 void print (char * str)  
 {  
  cout << str << '\n';  
 }  
   
 int main () {  
  const char * c = "sample text";  
  print ( const_cast<char *> (c) );  
  return 0;  
 }  

Đối số của hàm print là char* trong khi đó đầu vào là const char*, vì vậy phải loại bỏ tính chất const này đi bằng const_cast nếu không sẽ bị lỗi
haha
 error: invalid conversion from 'const char*' to 'char*'  

Xem thêm tại:
link1 
link2

Leave a Reply

Subscribe to Posts | Subscribe to Comments

- Copyright © Lập trình hệ thống nhúng Linux . Powered by Luong Duy Ninh -