Konversi Tipe dalam C++


Casting Tipe

Mengkonversi sebuah ekspresi dari tipe yang diberikan dalam jenis lain dikenal sebagai jenis-casting.Kita telah melihat beberapa cara untuk melemparkan ketik:

Konversi implisit

implisit konversi tidak memerlukan operator manapun. Mereka secara otomatis dilakukan ketika nilai akan disalin ke sebuah tipe yang kompatibel. Sebagai contoh:

1
2
3
pendek 2000 =,
int b,
b = a;

Di sini, nilai telah dipromosikan dari pendek int dan kita tidak harus menentukan segala-casting tipe operator. Ini dikenal sebagai konversi standar. Standar konversi mempengaruhi data jenis fundamental, dan memungkinkan konversi seperti konversi antara tipe numerik (singkat ke int, int ke float, double ke int …), ke atau dari bool, dan beberapa konversi pointer. Beberapa dari konversi ini dapat diartikan hilangnya presisi, yang compiler dapat sinyal dengan peringatan. Hal ini dapat dihindari dengan konversi eksplisit.

konversi implisit juga mencakup atau operator konversi konstruktor, yang mempengaruhi kelas-kelas yang mencakup konstruktor spesifik atau fungsi operator untuk melakukan konversi. Sebagai contoh:

1
2
3
4
5
kelas A {};
kelas B {public: B (A a) {}};

A,
B b = a;

Di sini, sebuah konversi implisit terjadi antara objek kelas A dan kelas B, karena B memiliki konstruktor yang mengambil sebuah objek dari kelas A sebagai parameter. Oleh karena itu konversi implisit dari A ke B diperbolehkan.

Explicit konversi

C + + adalah bahasa yang kuat-diketik. Banyak konversi, khususnya mereka yang menyiratkan interpretasi yang berbeda dari nilai, memerlukan konversi eksplisit. Kita telah melihat dua notasi untuk konversi tipe eksplisit: fungsional dan c-seperti casting:

1
2
3
4
pendek = 2000;
int b,
b = (int) a; / /  seperti notasi cast
c-b= int (a); / / notasi fungsional

Menjamin fungsionalitas dari operator konversi eksplisit adalah cukup untuk kebutuhan yang paling mendasar dengan tipe data. Namun, operator dapat diterapkan tanpa pandang bulu di kelas dan pointer ke kelas, yang dapat menyebabkan kode yang sementara sintaksis benar dapat menyebabkan error runtime. Sebagai contoh, kode berikut ini sintaktis benar:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/ / kelas jenis-casting
# include <iostream.h>
using namespace std;

kelas CDummy
{floati,
j;};

CAddition kelas
{intx, y;
publik:
CAddition (int a, int b) {x = a, y = b;}
int hasil () {return x +
y;}};

int main ()
{CDummyd;
CAddition * padd;
padd = CAddition *) &d;(();
cout <<hasil padd->
return
0;}

Program ini menyatakan pointer ke CAddition, tapi kemudian akan menetapkan untuk itu referensi ke objek jenis lain yang tidak kompatibel menggunakan eksplisit casting tipe:

padd = (CAddition *) &d;

Tradisional casting eksplisit-tipe memungkinkan untuk mengubah penunjuk apapun ke dalam jenis pointer lain, terpisah dari jenis mereka menunjukkan. Panggilan berikutnya untuk menghasilkan anggota akan menghasilkan baik-time error menjalankan atau hasil yang tak terduga.

Dalam rangka untuk mengontrol jenis konversi antara kelas, kita memiliki empat operator casting spesifik: dynamic_cast, reinterpret_cast, static_cast dan const_cast. format mereka adalah untuk mengikuti tipe baru tertutup antara sudut-kurung (<>) dan segera setelah itu, ekspresi yang akan dikonversikan antara tanda kurung.

dynamic_cast <new_type> (ekspresi)
<new_type> reinterpret_cast (ekspresi)
static_cast <new_type> (ekspresi)
<new_type> const_cast (ekspresi)

Casting tradisional setara tipe ekspresi ini akan menjadi:

(New_type)ungkapan
new_type(ekspresi)

tetapi masing-masing dengan karakteristiknya sendiri yang khusus:

dynamic_cast

dynamic_cast dapat digunakan hanya dengan pointer dan referensi ke obyek. Tujuannya adalah untuk memastikan bahwa hasil konversi tipe obyek yang lengkap yang valid dari kelas diminta.

Oleh karena itu, dynamic_cast selalu berhasil ketika kita melemparkan kelas ke salah satu kelas dasar nya:

1
2
3
4
5
6
7
8
kelas CBase {};
CDerived kelas: CBase public {};

CBase b; CBase pb *;
CDerived d; CDerived * pd;

pb = dynamic_cast <CBase*> (& d); / / ok:-untuk-baseberasal
pd= dynamic_cast <CDerived*> (& b); / / salah: base-ke-turunan

Konversi kedua potongan kode ini akan menghasilkan kesalahan kompilasi sejak-ke-turunan konversi dasar tidak diperbolehkan dengan dynamic_cast kecuali kelas dasar adalah polimorfik.

Ketika kelas adalah polimorfik, dynamic_cast melakukan pemeriksaan khusus selama runtime untuk memastikan bahwa ungkapan menghasilkan objek yang lengkap yang valid dari kelas diminta:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/ ​​/ dynamic_cast
# include <iostream.h>
# include <exception>
using namespace std;

kelas CBase dummy {virtual void () {}};
CDerived kelas: CBase public {int a;};

int main ()
{try{CBase
* PBA = CDerived baru;
CBase * PBB = CBase baru;
CDerived * pd;

pd = dynamic_cast <CDerived*> (PBA),
jika (pd == 0) cout <<“Null pointer pada cast pertama ketik” <<endl;

pd = <CDerived*> dynamic_cast (PBB),
jika (pd == 0) cout <<“Null pointer pada cast kedua tipe” <<endl;

} Catch (kecuali & e) {cout <<“Exception:” <e.what <();}
return
0;}

penunjuk Null pada kedua tipe cast
Kompatibilitas catatan: dynamic_cast membutuhkan Run-Time Jenis Informasi (bisa menghentikan) untuk melacak jenis dinamis. Beberapa compiler mendukung fitur ini sebagai pilihan yang dinonaktifkan secara default. Ini harus diaktifkan untuk memeriksa jenis runtime menggunakan dynamic_cast untuk bekerja dengan baik.

Kode mencoba untuk melakukan dua dinamis gips dari obyek penunjuk dari * CBase jenis (PBA dan PBB) untuk objek penunjuk dari tipe CDerived *, tetapi hanya yang pertama berhasil. mereka masing-masing Perhatikan inisialisasi:

1
2
CBase * PBA = baru CDerived;
CBase * PBB = CBase baru;

Meskipun keduanya pointer dari * CBase tipe, poin PBA untuk sebuah objek dari tipe CDerived, sementara poin PBB untuk objek CBase tipe. Jadi, ketika jenis mereka masing-tuang dilakukan menggunakan dynamic_cast, PBA menunjuk ke objek penuh kelas CDerived, sedangkan PBB menunjuk ke objek CBase kelas, yang merupakan objek tidak lengkap dari kelas CDerived.

Ketika dynamic_cast tidak dapat melemparkan pointer karena itu bukan objek lengkap yang diperlukan kelas-seperti pada konversi kedua dalam contoh sebelumnya-ia mengembalikan pointer null untuk mengindikasikan kegagalan. Jika dynamic_cast digunakan untuk mengkonversi ke tipe referensi dan konversi tidak mungkin, suatu pengecualian bad_cast tipe dilemparkan sebagai gantinya.

dynamic_cast juga dapat melemparkan pointer null bahkan antara pointer ke kelas yang tidak terkait, dan juga dapat cast pointer dari jenis apa pun untuk membatalkan pointer (* void).

static_cast

static_castdapat melakukan konversi antara pointer ke kelas yang terkait, tidak hanya dari kelas turunan ke basis, tetapi juga dari kelas dasar untuk menjadi produk turunan. Hal ini memastikan bahwa setidaknya kelas kompatibel jika objek yang tepat akan diubah, namun tidak ada pemeriksaan keamanan yang dilakukan selama runtime untuk memeriksa apakah obyek yang dikonversi pada kenyataannya merupakan objek penuh dari jenis tujuan. Oleh karena itu, terserah kepada programmer untuk memastikan bahwa konversi tersebut aman. Di sisi lain, overhead dari keselamatan-cek jenis dynamic_cast dihindari.

1
2
3
4
kelas CBase {};
CDerived kelas: CBase public {};
CBase * a CBase baru =;
CDerived * b <CDerived*> static_cast = (a);

Ini akan berlaku, meskipun b akan menunjuk ke suatu objek lengkap kelas dan dapat menyebabkan error runtime jika dereferenced.

static_cast juga dapat digunakan untuk melakukan setiap konversi non-pointer lain yang juga dapat dilakukan secara implisit, seperti untuk standar konversi misalnya antara tipe fundamental:

1
2
double d = 3,14159265;
int i = <int> static_cast (d);

Atau konversi antara kelas dengan konstruktor eksplisit atau fungsi operator Anda seperti diuraikan dalam “konversi implisit” di atas.

reinterpret_cast

reinterpret_castmengkonversi semua jenis penunjuk untuk semua jenis pointer lain, bahkan dari kelas yang tidak terkait. Hasil operasi salinan biner sederhana nilai dari satu pointer ke yang lain. Semua konversi pointer diperbolehkan: baik isi maupun menunjuk tipe pointer itu sendiri diperiksa.

Hal ini juga dapat cast pointer ke atau dari tipe integer. Format di mana nilai ini merupakan pointer integer adalah platform-khusus. Jaminan satu-satunya adalah bahwa seorang tokoh pointer ke tipe integer cukup besar untuk sepenuhnya berisi itu, diberikan untuk dapat dibuang kembali ke pointer yang valid.

Konversi yang dapat dilakukan oleh reinterpret_cast tetapi tidak oleh static_cast tidak menggunakan spesifik di C + + yang rendah tingkat operasi, yang hasil interpretasi dalam kode yang umumnya sistem-spesifik, dan dengan demikian non-portabel. Sebagai contoh:

1
2
3
4
kelas A {};
kelas B {};
A * A baru =;
B * b <B*> reinterpret_cast = (a);

Ini berlaku C + + kode, meskipun tidak masuk akal, karena sekarang kami memiliki pointer yang menunjuk ke suatu objek dari kelas yang tidak kompatibel, dan dengan demikian dereferencing itu tidak aman.

const_cast

Jenis casting memanipulasi constness suatu objek, baik untuk mengatur atau untuk dihapus. Sebagai contoh, untuk melewati sebuah argumen const ke fungsi yang mengharapkan-konstanta parameter non:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/ / const_cast
# include <iostream.h>
using namespace std;

void cetak (char * str)
{cout
<<str
<<endl;}

int main ()
{constchar * c = “contoh teks”;
cetak (*> <char const_cast (c));
return
0;}

contoh teks

typeid

typeidmemungkinkan untuk memeriksa jenis ekspresi:

typeid (ekspresi)

Operator ini mengembalikan referensi ke obyek konstan type_info tipe yang didefinisikan dalam file header <typeinfo> standar. Nilai ini kembali dapat dibandingkan dengan satu lagi operator yang menggunakan == dan! = Atau dapat berfungsi untuk memperoleh diakhiri karakter urutan-null mewakili tipe data atau nama kelas dengan menggunakan namanya () anggota.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/ / typeid
# include <iostream.h>
# include <typeinfo>
using namespace std;

int main ()
{int* a, b,
a = 0 b = 0;
if (typeid (a))! = typeid (b)
{cout
<<“a dan b adalah jenis yang berbeda: \ n”;
pengadilan <<“adalah:” <<typeid (a)  nama () n <<‘\’;
“.cout <<” b adalah: <typeid (b). <name () <‘<‘ \
n;}
return
0;}

a dan b adalah jenisberbeda:
yangadalah:*
bint:int

Ketika typeid diterapkan untuk kelas typeid menggunakan bisa menghentikan untuk melacak jenis objek dinamis. Ketika typeid diterapkan ke sebuah ekspresi yang tipe kelas polimorfik, hasilnya adalah jenis lengkap diturunkan dari objek yang paling:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/ / typeid, kelas polimorfik
# include <iostream.h>
# include <typeinfo>
# include <exception>
using namespace std;

kelas CBase {virtual void f () {}};
CDerived kelas: CBase public {};

int main ()
{try{CBase
* a CBase baru =;
CBase * b = new CDerived;
<cout <adalah: “<<(typeid a).” nama () <‘<‘ \ n;
cout <<” b adalah: “<<typeid (b)  Nama () n <<‘\’;
<.<pengadilan” * adalah: “<<typeid (* a)  Nama () n <<‘\’
<.pengadilan;<“* b adalah:” <<typeid (* b)  nama () n
“.<<‘\’;}catch (kecuali & e) {cout <<” Pengecualian: <e.what <() <<endl; }
return
0;}

adalah: CBase kelas *
b adalah: kelas CBase *
* adalah: kelas CBase
* b adalah: kelas CDerived

Perhatikan bagaimana tipe yang typeid mempertimbangkan untuk pointer adalah jenis pointer itu sendiri (a dan b adalah jenis kelas CBase *). Namun, ketika typeid diterapkan untuk obyek (seperti * a * dan b) menghasilkan typeid tipe dinamis mereka (yaitu jenis objek yang paling lengkap berasal).

Jika jenis typeid mengevaluasi adalah pointer didahului oleh operator dereference (*), dan pointer ini memiliki nilai null, typeid melemparkan bad_typeid pengecualian.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: