Secara internal dan tentang kode yang dihasilkan, apakah benar-benar ada perbedaan antara:
MyClass::MyClass(): _capacity(15), _data(NULL), _len(0)
{
}
dan
MyClass::MyClass()
{
_capacity=15;
_data=NULL;
_len=0
}
Terima kasih...
Jawaban:
Dengan asumsi bahwa nilai-nilai tersebut adalah tipe primitif, maka tidak, tidak ada perbedaan. Daftar inisialisasi hanya membuat perbedaan ketika Anda memiliki objek sebagai anggota, karena alih-alih menggunakan inisialisasi default yang diikuti dengan penugasan, daftar inisialisasi memungkinkan Anda menginisialisasi objek ke nilai akhirnya. Ini sebenarnya bisa terasa lebih cepat.
Anda perlu menggunakan daftar inisialisasi untuk menginisialisasi anggota konstan, referensi, dan kelas dasar
Saat Anda perlu menginisialisasi anggota konstan, referensi, dan parameter meneruskan ke konstruktor kelas dasar, seperti yang disebutkan dalam komentar, Anda perlu menggunakan daftar inisialisasi.
struct aa
{
int i;
const int ci; // constant member
aa() : i(0) {} // will fail, constant member not initialized
};
struct aa
{
int i;
const int ci;
aa() : i(0) { ci = 3;} // will fail, ci is constant
};
struct aa
{
int i;
const int ci;
aa() : i(0), ci(3) {} // works
};
Contoh kelas / struct (tidak lengkap) berisi referensi:
struct bb {};
struct aa
{
bb& rb;
aa(bb& b ) : rb(b) {}
};
// usage:
bb b;
aa a(b);
Dan contoh inisialisasi kelas dasar yang membutuhkan parameter (mis. Tidak ada konstruktor default):
struct bb {};
struct dd
{
char c;
dd(char x) : c(x) {}
};
struct aa : dd
{
bb& rb;
aa(bb& b ) : dd('a'), rb(b) {}
};
_capacity
, _data
dan _len
memiliki tipe kelas tanpa konstruktor default yang dapat diakses?
const
anggota dalam tubuh konstruktor, Anda harus menggunakan daftar inisialisasi - non const
anggota dapat diinisialisasi dalam daftar inisialisasi atau dalam badan konstruktor.
Iya. Dalam kasus pertama, Anda dapat mendeklarasikan _capacity
, _data
dan _len
sebagai konstanta:
class MyClass
{
private:
const int _capacity;
const void *_data;
const int _len;
// ...
};
Ini akan menjadi penting jika Anda ingin memastikan const
-ness variabel instance ini saat menghitung nilainya pada waktu proses, misalnya:
MyClass::MyClass() :
_capacity(someMethod()),
_data(someOtherMethod()),
_len(yetAnotherMethod())
{
}
const
instance harus diinisialisasi dalam daftar penginisialisasi atau tipe yang mendasari harus menyediakan konstruktor tanpa parameter publik (yang dilakukan oleh tipe primitif).
Saya pikir tautan ini http://www.cplusplus.com/forum/articles/17820/ memberikan penjelasan yang sangat baik - terutama bagi mereka yang baru mengenal C ++.
Alasan mengapa daftar intialiser lebih efisien adalah karena di dalam badan konstruktor, hanya penugasan yang dilakukan, bukan inisialisasi. Jadi, jika Anda berurusan dengan tipe non-built-in, konstruktor default untuk objek itu telah dipanggil sebelum isi konstruktor dimasukkan. Di dalam badan konstruktor, Anda memberikan nilai ke objek itu.
Akibatnya, ini adalah panggilan ke konstruktor default yang diikuti dengan panggilan ke operator penugasan salinan. Daftar penginisialisasi memungkinkan Anda memanggil konstruktor salinan secara langsung, dan ini terkadang jauh lebih cepat (ingat bahwa daftar penginisialisasi ada sebelum badan konstruktor)
Saya akan menambahkan bahwa jika Anda memiliki anggota tipe kelas tanpa konstruktor default yang tersedia, inisialisasi adalah satu-satunya cara untuk membangun kelas Anda.
Perbedaan besar adalah bahwa tugas dapat menginisialisasi anggota kelas induk; penginisialisasi hanya bekerja pada anggota yang dideklarasikan pada lingkup kelas saat ini.
Tergantung pada jenis yang terlibat. Perbedaannya serupa di antara keduanya
std::string a;
a = "hai";
dan
std::string a("hai");
di mana bentuk kedua adalah daftar inisialisasi- yaitu, membuat perbedaan jika tipe memerlukan argumen konstruktor atau lebih efisien dengan argumen konstruktor.
Perbedaan sebenarnya terletak pada bagaimana compiler gcc menghasilkan kode mesin dan meletakkan memori. Menjelaskan:
Pasti ada cara lain untuk menangani anggota tipe const. Tetapi untuk memudahkan hidup mereka, penulis kompilator gcc memutuskan untuk menyiapkan beberapa aturan
Hanya ada satu cara untuk menginisialisasi instance kelas dasar dan variabel anggota non-statis dan itu menggunakan daftar penginisialisasi.
Jika Anda tidak menentukan variabel anggota dasar atau non-statis dalam daftar penginisialisasi konstruktor Anda, maka anggota atau basis tersebut akan diinisialisasi secara default (jika anggota / basis adalah jenis kelas non-POD atau array kelas non-POD jenis) atau dibiarkan tidak dimulai sebaliknya.
Setelah badan konstruktor dimasukkan, semua basis atau anggota akan diinisialisasi atau dibiarkan tidak diinisialisasi (yaitu mereka akan memiliki nilai tak tentu). Tidak ada kesempatan dalam badan konstruktor untuk mempengaruhi bagaimana mereka harus diinisialisasi.
Anda mungkin dapat menetapkan nilai baru untuk anggota dalam badan konstruktor tetapi tidak mungkin untuk menetapkan const
anggota atau anggota jenis kelas yang telah dibuat non-assignable dan tidak mungkin untuk rebind referensi.
Untuk tipe bawaan dan beberapa tipe yang ditentukan pengguna, menetapkan dalam badan konstruktor mungkin memiliki efek yang sama persis seperti menginisialisasi dengan nilai yang sama di daftar penginisialisasi.
Jika Anda gagal menamai anggota atau basis dalam daftar penginisialisasi dan entitas tersebut adalah referensi, memiliki tipe kelas tanpa konstruktor default yang dideklarasikan pengguna yang dapat diakses, const
memenuhi syarat dan memiliki tipe POD atau merupakan tipe kelas POD atau larik tipe kelas POD berisi anggota yang const
memenuhi syarat (secara langsung atau tidak langsung) maka program tersebut tidak berbentuk.
Jika Anda menulis daftar penginisialisasi, Anda melakukan semuanya dalam satu langkah; jika Anda tidak menulis daftar initilizer, Anda akan melakukan 2 langkah: satu untuk deklarasi dan satu lagi untuk menambahkan nilainya.
Ada perbedaan antara daftar inisialisasi dan pernyataan inisialisasi dalam konstruktor. Mari pertimbangkan kode di bawah ini:
#include <initializer_list>
#include <iostream>
#include <algorithm>
#include <numeric>
class MyBase {
public:
MyBase() {
std::cout << __FUNCTION__ << std::endl;
}
};
class MyClass : public MyBase {
public:
MyClass::MyClass() : _capacity( 15 ), _data( NULL ), _len( 0 ) {
std::cout << __FUNCTION__ << std::endl;
}
private:
int _capacity;
int* _data;
int _len;
};
class MyClass2 : public MyBase {
public:
MyClass2::MyClass2() {
std::cout << __FUNCTION__ << std::endl;
_capacity = 15;
_data = NULL;
_len = 0;
}
private:
int _capacity;
int* _data;
int _len;
};
int main() {
MyClass c;
MyClass2 d;
return 0;
}
Ketika MyClass digunakan, semua anggota akan diinisialisasi sebelum pernyataan pertama dalam konstruktor dijalankan.
Tapi, ketika MyClass2 digunakan, semua anggota tidak diinisialisasi ketika pernyataan pertama dalam konstruktor dijalankan.
Dalam kasus selanjutnya, mungkin ada masalah regresi ketika seseorang menambahkan beberapa kode dalam konstruktor sebelum anggota tertentu diinisialisasi.
Inilah poin di mana saya tidak melihat orang lain merujuknya:
class temp{
public:
temp(int var);
};
Kelas temp tidak memiliki ctor default. Saat kami menggunakannya di kelas lain sebagai berikut:
class mainClass{
public:
mainClass(){}
private:
int a;
temp obj;
};
kode tidak akan dikompilasi, karena kompilator tidak tahu bagaimana menginisialisasi obj
, karena ia hanya memiliki ctor eksplisit yang menerima nilai int, jadi kita harus mengubah ctor sebagai berikut:
mainClass(int sth):obj(sth){}
Jadi, ini bukan hanya tentang const dan referensi!