Saya menemukan potongan kode aneh ini yang mengkompilasi dengan baik:
class Car
{
public:
int speed;
};
int main()
{
int Car::*pSpeed = &Car::speed;
return 0;
}
Mengapa C ++ memiliki pointer ini ke anggota data non-statis kelas? Apa gunanya pointer aneh ini dalam kode nyata?
Jawaban:
Ini adalah "penunjuk ke anggota" - kode berikut menggambarkan penggunaannya:
Seperti mengapa Anda ingin melakukan itu, baik itu memberi Anda tingkat tipuan lain yang dapat memecahkan beberapa masalah rumit. Tapi jujur saja, saya belum pernah menggunakannya dalam kode saya sendiri.
Sunting: Saya tidak bisa memikirkan penggunaan yang meyakinkan untuk pointer ke data anggota. Pointer ke fungsi anggota dapat digunakan dalam arsitektur pluggable, tetapi sekali lagi menghasilkan contoh di ruang kecil mengalahkan saya. Berikut ini adalah yang terbaik (belum diuji) coba - fungsi Terapkan yang akan melakukan beberapa pemrosesan pra & pasca sebelum menerapkan fungsi anggota yang dipilih pengguna ke objek:
Tanda kurung
c->*func
diperlukan karena->*
operator memiliki prioritas lebih rendah daripada operator fungsi panggilan.sumber
Ini adalah contoh paling sederhana yang dapat saya pikirkan yang menyampaikan kasus-kasus langka di mana fitur ini berkaitan:
Yang perlu diperhatikan di sini adalah pointer yang diteruskan ke count_fruit. Ini menghemat Anda harus menulis fungsi count_apples dan count_oranges terpisah.
sumber
&bowls.apples
dan&bowls.oranges
?&bowl::apples
dan&bowl::oranges
tidak menunjuk apa pun.&bowl::apples
dan&bowl::oranges
tidak menunjuk ke anggota suatu objek ; mereka menunjuk anggota kelas . Mereka perlu dikombinasikan dengan pointer ke objek yang sebenarnya sebelum mereka menunjuk ke sesuatu. Kombinasi itu dicapai dengan->*
operator.Aplikasi lain adalah daftar yang mengganggu. Tipe elemen dapat memberi tahu daftar apa pointer berikutnya / prev. Jadi daftar ini tidak menggunakan nama yang dikodekan tetapi masih dapat menggunakan pointer yang ada:
sumber
next
.Inilah contoh dunia nyata yang saya kerjakan saat ini, dari pemrosesan sinyal / sistem kontrol:
Misalkan Anda memiliki beberapa struktur yang mewakili data yang Anda kumpulkan:
Sekarang anggaplah Anda memasukkan mereka ke dalam vektor:
Sekarang anggaplah Anda ingin menghitung beberapa fungsi (katakanlah mean) dari salah satu variabel pada rentang sampel, dan Anda ingin memasukkan perhitungan rata-rata ini ke dalam suatu fungsi. Pointer-ke-anggota memudahkan:
Catatan Diedit 2016/08/05 untuk pendekatan fungsi-templat yang lebih ringkas
Dan, tentu saja, Anda bisa templat untuk menghitung rata-rata untuk forward-iterator dan semua tipe nilai yang mendukung penambahan dengan dirinya sendiri dan pembagian dengan size_t:
EDIT - Kode di atas memiliki implikasi kinerja
Anda harus mencatat, karena saya segera menemukan, bahwa kode di atas memiliki beberapa implikasi kinerja yang serius. Ringkasannya adalah bahwa jika Anda menghitung statistik ringkasan pada deret waktu, atau menghitung FFT dll, maka Anda harus menyimpan nilai untuk setiap variabel yang bersebelahan dalam memori. Jika tidak, mengulangi seri akan menyebabkan cache hilang untuk setiap nilai yang diambil.
Pertimbangkan kinerja kode ini:
Pada banyak arsitektur, satu instance dari
Sample
akan mengisi baris cache. Jadi pada setiap iterasi loop, satu sampel akan ditarik dari memori ke dalam cache. 4 byte dari garis cache akan digunakan dan sisanya dibuang, dan iterasi berikutnya akan menghasilkan cache lain yang hilang, akses memori dan sebagainya.Jauh lebih baik untuk melakukan ini:
Sekarang ketika nilai x pertama dimuat dari memori, tiga berikutnya juga akan dimuat ke dalam cache (seandainya penyelarasan yang sesuai), artinya Anda tidak perlu nilai apa pun dimuat untuk tiga iterasi berikutnya.
Algoritme di atas dapat ditingkatkan sedikit lebih jauh melalui penggunaan instruksi SIMD pada misalnya arsitektur SSE2. Namun, ini bekerja jauh lebih baik jika semua nilai bersebelahan dalam memori dan Anda dapat menggunakan instruksi tunggal untuk memuat empat sampel bersama-sama (lebih banyak di versi SSE nanti).
YMMV - desain struktur data Anda agar sesuai dengan algoritma Anda.
sumber
double Sample::*
itu kuncinya!Anda nanti dapat mengakses anggota ini, dalam hal apa pun :
Perhatikan bahwa Anda perlu sebuah instance untuk memanggilnya, sehingga tidak berfungsi seperti delegasi.
Ini jarang digunakan, saya membutuhkannya mungkin sekali atau dua kali selama bertahun-tahun.
Biasanya menggunakan antarmuka (yaitu kelas dasar murni dalam C ++) adalah pilihan desain yang lebih baik.
sumber
IBM memiliki beberapa dokumentasi lebih lanjut tentang cara menggunakan ini. Secara singkat, Anda menggunakan pointer sebagai offset ke dalam kelas. Anda tidak dapat menggunakan petunjuk ini selain dari kelas yang mereka maksud, jadi:
Tampaknya sedikit tidak jelas, tetapi satu aplikasi yang mungkin adalah jika Anda mencoba menulis kode untuk deserialisasi data generik menjadi banyak jenis objek yang berbeda, dan kode Anda perlu menangani jenis objek yang sama sekali tidak diketahui (misalnya, kode Anda adalah di perpustakaan, dan objek tempat Anda deserialize dibuat oleh pengguna perpustakaan Anda). Pointer anggota memberi Anda cara umum, semi-terbaca untuk merujuk ke offset anggota data individu, tanpa harus menggunakan kekosongan * tipuan tipuan cara Anda mungkin untuk C struct.
sumber
Itu memungkinkan untuk mengikat variabel dan fungsi anggota secara seragam. Berikut ini adalah contoh dengan kelas Mobil Anda. Penggunaan yang lebih umum akan mengikat
std::pair::first
dan::second
saat digunakan dalam algoritma STL dan Tingkatkan pada peta.sumber
Anda dapat menggunakan larik pointer untuk data anggota (homogen) untuk mengaktifkan antarmuka ganda, bernama anggota (iexdata) dan array-subscript (yaitu x [idx]).
sumber
union
tipe-to dengan cara itu tidak diizinkan oleh standar karena memunculkan berbagai bentuk perilaku yang tidak terdefinisi ... sedangkan jawaban ini ok.float *component[] = { &x, &y, &z }; return *component[idx];
Yaitu, pointer-ke-komponen tampaknya tidak memiliki tujuan selain kebingungan.Salah satu cara saya menggunakannya adalah jika saya memiliki dua implementasi tentang bagaimana melakukan sesuatu di kelas dan saya ingin memilih satu pada saat run-time tanpa harus terus menerus melalui pernyataan if yaitu
Jelas ini hanya berguna secara praktis jika Anda merasa kode sedang dipalu sehingga pernyataan if memperlambat hal-hal yang dilakukan misalnya. jauh di dalam nyali dari beberapa algoritma intensif di suatu tempat. Saya masih berpikir itu lebih elegan daripada pernyataan if bahkan dalam situasi di mana tidak memiliki penggunaan praktis tapi itu hanya pendapat saya.
sumber
Algorithm
dan dua kelas turunan, misalnya,AlgorithmA
danAlgorithmB
. Dalam kasus seperti itu, kedua algoritma dipisahkan dengan baik dan dipastikan akan diuji secara independen.Pointer ke kelas bukan pointer nyata ; kelas adalah konstruk logis dan tidak memiliki keberadaan fisik dalam memori, namun, ketika Anda membangun pointer ke anggota kelas, ia memberikan offset ke objek kelas anggota di mana anggota dapat ditemukan; Ini memberikan kesimpulan penting: Karena anggota statis tidak terkait dengan objek apa pun maka penunjuk ke anggota TIDAK BISA menunjuk ke anggota statis (data atau fungsi) apa pun Pertimbangkan hal berikut:
Sumber: Referensi Lengkap C ++ - Herbert Schildt 4th Edition
sumber
Saya pikir Anda hanya ingin melakukan ini jika data anggota cukup besar (misalnya, objek dari kelas yang cukup besar), dan Anda memiliki beberapa rutin eksternal yang hanya bekerja pada referensi ke objek dari kelas itu. Anda tidak ingin menyalin objek anggota, jadi ini memungkinkan Anda menyebarkannya.
sumber
Berikut adalah contoh di mana penunjuk ke anggota data dapat bermanfaat:
sumber
Misalkan Anda memiliki struktur. Di dalam struktur itu adalah * semacam nama * dua variabel dari jenis yang sama tetapi dengan makna yang berbeda
Oke, sekarang katakanlah Anda memiliki banyak
foo
s dalam sebuah wadah:Oke, sekarang anggaplah Anda memuat data dari sumber yang berbeda, tetapi data disajikan dengan cara yang sama (misalnya, Anda memerlukan metode penguraian yang sama).
Anda dapat melakukan sesuatu seperti ini:
Pada titik ini, panggilan
readValues()
akan mengembalikan sebuah wadah dengan serentetan "input-a" dan "input-b"; semua kunci akan ada, dan foos dengan memiliki a atau b atau keduanya.sumber
Hanya untuk menambahkan beberapa use case untuk jawaban @ anon's & @ Oktalist, berikut adalah bahan bacaan yang bagus tentang fungsi pointer-to-anggota dan data pointer-ke-anggota.
https://www.dre.vanderbilt.edu/~schmidt/PDF/C++-ptmf4.pdf
sumber