Dalam C++, apakah ada perbedaan antara:
struct Foo { ... };
dan
typedef struct { ... } Foo;
Dalam C++, hanya ada perbedaan yang halus. It's peninggalan dari C, di mana itu membuat perbedaan.
Bahasa C standar (C89 §3.1.2.3, C99 §6.2.3, dan C11 §6.2.3) mandat terpisah namespaces untuk kategori yang berbeda dari pengidentifikasi, termasuk tag identifiers (untuk struct
/uni
/enum
) dan ordinary identifiers (untuk typedef
dan pengenal lainnya).
Jika anda hanya mengatakan:
struct Foo { ... };
Foo x;
anda akan mendapatkan kesalahan kompiler, karena Foo
hanya didefinisikan dalam tag namespace.
Anda'd harus mendeklarasikan sebagai:
struct Foo x;
Setiap kali anda ingin merujuk ke Foo
, anda'd selalu harus menyebutnya struct Foo
. Ini akan menjengkelkan cepat, sehingga anda dapat menambahkan typedef
:
struct Foo { ... };
typedef struct Foo Foo;
Sekarang struct Foo
(di tag namespace) dan sekadar Foo
(biasa pengenal namespace) kedua merujuk pada hal yang sama, dan anda dapat dengan bebas menyatakan benda-benda dari jenis Foo
tanpa struct
kata kunci.
Construct:
typedef struct Foo { ... } Foo;
hanya sebuah singkatan untuk deklarasi dan typedef
.
Akhirnya,
typedef struct { ... } Foo;
menyatakan anonim struktur dan menciptakan typedef
untuk itu. Dengan demikian, dengan membangun ini, itu doesn't memiliki nama di tag nama, hanya nama di typedef namespace. Ini berarti ia juga tidak dapat maju-menyatakan. Jika anda ingin membuat sebuah deklarasi kedepan, anda harus memberikan nama pada tag namespace.
Dalam C++, semua struct
/uni
/enum
/kelas
deklarasi bertindak seperti mereka yang secara implisit typedef
'ed, asalkan nama tidak tersembunyi oleh deklarasi lain dengan nama yang sama. Lihat Michael Duri's jawaban untuk rincian lengkap.
Dalam DDJ artikel, Dan Saks menjelaskan satu area kecil di mana bug dapat merayap melalui jika anda tidak typedef anda struct (dan kelas-kelas!):
Jika anda ingin, anda dapat membayangkan bahwa C++ menghasilkan typedef untuk setiap tag nama, seperti
typedef kelas string string;
Sayangnya, hal ini tidak sepenuhnya akurat. Saya berharap itu adalah yang sederhana, tapi's tidak. C++ dapat't menghasilkan seperti typedefs untuk struct, serikat pekerja, atau enums tidak kompatibel tanpa memperkenalkan dengan C.
Untuk contoh, misalkan sebuah program C menyatakan kedua fungsi dan struct bernama status:
int status(); struct status;
sekali Lagi, ini dapat menjadi praktek yang buruk, tapi ini adalah C. Dalam program ini, status (oleh sendiri) mengacu pada fungsi; struct status mengacu pada jenis.
Jika C++ tidak secara otomatis menghasilkan typedefs untuk kategori, maka ketika anda menyusun program seperti C++, compiler akan menghasilkan:
typedef struct status status;
Sayangnya, jenis nama akan konflik dengan nama fungsi, dan program tidak akan mengkompilasi. Yang's mengapa C++ dapat't hanya menghasilkan typedef untuk masing-masing tag.
Dalam C++, kategori bertindak seperti typedef nama, kecuali bahwa program dapat menyatakan suatu objek, fungsi, atau enumerator dengan nama yang sama dan lingkup yang sama sebagai tag. Dalam kasus itu, objek, fungsi, atau enumerator nama menyembunyikan nama tag. Program ini dapat merujuk pada nama tag hanya dengan menggunakan kata kunci class, struct, union, atau enum (sesuai) di depan nama tag. Nama jenis terdiri dari salah satu kata kunci ini diikuti oleh tag ini diuraikan tipe-specifier. misalnya, struct dan status enum bulan yang diuraikan tipe-specifier.
dengan Demikian, program C yang berisi:
int status(); struct status;
berperilaku sama ketika disusun sebagai C++. nama status sendiri mengacu pada fungsi. Program ini dapat merujuk ke jenis hanya dengan menggunakan diuraikan tipe-penspesifikasi struct status.
Jadi bagaimana hal ini memungkinkan serangga merayap ke program? Mempertimbangkan program di Daftar 1. Program ini mendefinisikan class foo dengan default constructor, dan konversi operator yang mengkonversi foo objek const char *. ekspresi
p = foo();
di utama harus membangun foo objek dan menerapkan konversi operator. Yang output berikutnya pernyataan
cout << p << '\n';
harus menampilkan class foo, tapi itu doesn't. Ini menampilkan fungsi foo.
Ini hasil yang mengejutkan terjadi karena program termasuk header lib.jam yang ditunjukkan dalam Daftar 2. Header ini mendefinisikan sebuah fungsi juga bernama foo. Yang nama fungsi foo menyembunyikan nama kelas foo, jadi referensi untuk foo di utama mengacu pada fungsi, bukan kelas. utama dapat merujuk ke kelas hanya dengan menggunakan diuraikan tipe-penspesifikasi, sebagai di
p = class foo();
cara untuk menghindari kebingungan seperti itu semua program ini adalah untuk menambah berikut typedef untuk nama kelas foo:
typedef class foo foo;
segera sebelum atau setelah kelas definisi. Ini typedef menyebabkan konflik antara jenis nama foo dan nama fungsi foo (dari perpustakaan) yang akan memicu compile-time error.
aku tahu tidak ada orang yang benar-benar menulis ini typedefs sebagai masalah tentu saja. Hal ini membutuhkan banyak disiplin. Sejak kejadian kesalahan seperti satu di Daftar 1 adalah mungkin cukup kecil, anda tidak pernah bertabrakan masalah ini. Tapi jika kesalahan anda software mungkin menyebabkan cedera tubuh, maka anda harus menulis typedefs tidak peduli bagaimana mungkin kesalahan.
aku't membayangkan mengapa siapa pun akan pernah ingin menyembunyikan nama kelas dengan fungsi atau nama objek yang sama ruang lingkup sebagai kelas. Bersembunyi aturan di C adalah sebuah kesalahan, dan mereka harus tidak telah diperpanjang untuk kelas-kelas di C++. Memang, anda dapat memperbaiki kesalahan, tetapi hal ini membutuhkan ekstra pemrograman disiplin dan usaha yang seharusnya tidak perlu.
Satu perbedaan penting: typedef tidak dapat maju menyatakan. Jadi untuk
typedefpilihan anda harus
#includefile yang berisi
typedef, yang berarti segala sesuatu yang
#include anda .h
juga termasuk file tersebut baik secara langsung kebutuhan-kebutuhan itu atau tidak, dan sebagainya. Itu pasti dapat berdampak anda membangun kali pada proyek yang lebih besar.
Tanpa typedef
, dalam beberapa kasus, anda hanya dapat menambahkan ke depan deklarasi struct Foo;
di atas .h
file, dan hanya #include
struct definisi dalam .cpp
file.
Ada adalah perbedaan, tapi halus. Lihatlah dengan cara ini: struct Foo
memperkenalkan tipe baru. Yang kedua menciptakan sebuah alias yang disebut Foo (dan bukan jenis baru) yang tidak disebutkan namanya struct
jenis.
7.1.3 Yang typedef penspesifikasi
1 [...]
Sebuah nama yang dinyatakan dengan typedef penspesifikasi menjadi typedef-nama. Dalam lingkup deklarasi, typedef-nama sintaksis yang setara dengan kata kunci dan nama-nama jenis terkait dengan identifier di cara yang dijelaskan di Pasal 8. Sebuah typedef-nama demikian sinonim untuk tipe lain. Sebuah typedef-nama tidak memperkenalkan jenis baru cara deklarasi kelas (9.1) atau deklarasi enum tidak.
8 Jika typedef deklarasi mendefinisikan yang tidak disebutkan namanya kelas (atau enum), pertama typedef-nama yang dinyatakan oleh deklarasi untuk yang tipe kelas (atau enum type) digunakan untuk menunjukkan tipe kelas (atau tipe enum) untuk linkage tujuan (3.5). [ Contoh:
typedef struct { } *ps, S; // S is the class name for linkage purposes
Jadi, typedef selalu digunakan sebagai pengganti/sinonim untuk tipe lain.
Anda dapat't menggunakan deklarasi maju dengan typedef struct.
Struct itu sendiri adalah anonim jenis, sehingga anda don't memiliki nama asli untuk maju menyatakan.
typedef struct{
int one;
int two;
}myStruct;
Maju deklarasi seperti ini tidak akan bekerja:
struct myStruct; //forward declaration fails
void blah(myStruct* pStruct);
//error C2371: 'myStruct' : redefinition; different basic types
Sebuah perbedaan penting antara 'typedef struct' dan 'struct' dalam C++ adalah inline anggota inisialisasi di 'typedef struct' tidak akan bekerja.
// the 'x' in this struct will NOT be initialised to zero
typedef struct { int x = 0; } Foo;
// the 'x' in this struct WILL be initialised to zero
struct Foo { int x = 0; };