- Back to Home »
- CPP »
- C++ Casting Operators
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:
+ upcast: converting pointer-to-derived to pointer-to-base
+ downcast: converting 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 base là Bar 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