Apakah ide yang bagus untuk "menentukan saya (* ini)"?

19

Makro ini dapat didefinisikan dalam beberapa tajuk global, atau lebih baik, sebagai parameter baris perintah kompiler:

#define me (*this)

Dan beberapa contoh penggunaan:

some_header.h:

inline void Update()
{
    /* ... */
}

main.cpp:

#include "some_header.h"

class A {
public:
    void SetX(int x)
    {
        me.x = x;   
        me.Update(); 
    }

    void SomeOtherFunction()
    {
        ::Update();
    }

    /*
        100 or more lines
        ... 
    */

    void Update()
    {
        // ... 
    }

    int x;  
};

Jadi dalam metode kelas ketika saya mengakses anggota kelas, saya selalu menggunakan me, dan ketika mengakses pengenal global saya selalu menggunakan ::. Ini memberikan pembaca yang tidak terbiasa dengan kode (mungkin saya sendiri setelah beberapa bulan) informasi lokal dari apa yang diakses tanpa perlu mencari di tempat lain. Saya ingin mendefinisikan mekarena saya menemukan menggunakan di this->mana - mana terlalu berisik dan jelek. Tapi bisakah #define me (*this)dianggap praktik C ++ yang bagus? Apakah ada beberapa poin masalah praktis dengan memakro? Dan jika Anda sebagai programmer C ++ akan menjadi pembaca beberapa kode menggunakan memakro, apakah Anda suka atau tidak?

Sunting: Karena banyak orang berargumen tidak menggunakan kontra secara spesifik me, tetapi pada umumnya menentang ini secara eksplisit. Saya pikir mungkin tidak jelas apa manfaat dari "eksplisit ini di mana-mana".

Apa manfaat dari "eksplisit ini di mana-mana"?

  • Sebagai pembaca kode Anda memiliki kepastian apa yang diakses dan Anda dapat berkonsentrasi pada hal-hal yang berbeda daripada memverifikasi - dalam beberapa kode yang jauh - yang benar-benar diakses apa yang Anda pikir diakses.
  • Anda dapat menggunakan fungsi pencarian secara lebih spesifik. Pencarian " this->x" dapat memberi Anda lebih banyak hasil yang diinginkan daripada hanya pencarian " x"
  • Ketika Anda menghapus atau mengganti nama beberapa anggota, kompiler dengan andal memberi tahu Anda di tempat-tempat di mana anggota ini digunakan. (Beberapa fungsi global dapat memiliki nama yang sama dan ada kemungkinan Anda dapat memperkenalkan kesalahan jika Anda tidak menggunakan ini secara eksplisit).
  • Ketika Anda refactoring kode dan membuat fungsi non-anggota dari anggota (untuk membuat enkapsulasi yang lebih baik) secara eksplisit ini menunjukkan kepada Anda tempat yang harus Anda edit dan Anda dapat dengan mudah mengganti ini dengan pointer ke instance kelas yang diberikan sebagai parameter fungsi non-anggota
  • Umumnya ketika Anda mengubah kode, ada lebih banyak kemungkinan kesalahan ketika Anda tidak menggunakan eksplisit ini daripada ketika Anda menggunakan eksplisit ini di mana-mana.
  • Secara eksplisit ini kurang berisik daripada eksplisit „m_“ ketika Anda mengakses anggota dari luar ( object.membervs object.m_member) (terima kasih kepada @Kaz untuk menemukan titik ini)
  • Secara eksplisit ini memecahkan masalah secara universal untuk semua anggota - atribut dan metode, sedangkan „m_“ atau awalan lainnya secara praktis hanya dapat digunakan untuk atribut.

Saya ingin memoles dan memperpanjang daftar ini, beri tahu saya jika Anda tahu tentang kelebihan lain dan gunakan case untuk ini secara eksplisit di mana-mana .

pengguna3123061
sumber
3
Anda harus menghindari argumen fungsi dan anggota dengan nama yang sama, serta menghindari eksplisit "ini".
pjc50
4
Mengingatkan saya pada kode VB atasan saya. Me Me Me dimana-mana. Kedengarannya egois. : p Pokoknya, jawabannya sejauh ini mengatakan itu semua.
MetalMikester
19
Itu ide yang bagus! Dan bagi mereka yang berasal dari latar belakang Python, mengapa tidak #define self (*this)? Anda bahkan dapat mencampur kedua makro dan memiliki beberapa file yang meniru VB dan yang lainnya Python. :)
logc
11
Mengapa tidak hanya pergi semua keluar, dan lakukan: #include "vb.h", #Include pascal.h, atau #include FOTRAN.hdan memiliki orang berikutnya untuk menyentuh kode Anda kirimkan ke TDWTF .
Dan Neely
4
Oh tolong, tidak. Anda bisa menyelamatkan diri dari masalah dengan hanya mendeklarasikan atribut sebagai me_x.
Gort the Robot

Jawaban:

90

Tidak, bukan itu.

Pikirkan programmer yang akan mempertahankan kode Anda beberapa tahun dari sekarang lama setelah Anda pergi untuk padang rumput yang lebih hijau dan mengikuti konvensi umum bahasa yang Anda gunakan. Dalam C ++, Anda hampir tidak perlu menulis this, karena kelas termasuk dalam urutan resolusi simbol dan ketika simbol ditemukan dalam ruang lingkup kelas, this->tersirat. Jadi jangan menulis seperti yang dilakukan semua orang.

Jika Anda sering bingung simbol mana yang berasal dari ruang lingkup kelas, pendekatan yang biasa menggunakan pola penamaan umum untuk anggota (bidang dan kadang-kadang metode pribadi; Saya belum melihatnya digunakan untuk metode publik). Yang umum termasuk suffixing dengan _atau awalan dengan m_atau m.

Jan Hudec
sumber
12
"Dalam C ++, Anda hampir tidak pernah harus menulis ini" itu adalah konvensi yang sama sekali tidak terkait dengan pertanyaan. Beberapa orang (seperti saya) lebih suka menulis thissecara eksplisit memperjelas bahwa variabel tersebut tidak lokal untuk metode ini. Pertanyaannya di sini adalah apakah makro meharus ada, bukan apakah thissesuatu harus digunakan.
Mehrdad
8
@Mehrdad: Karena OP secara eksplisit mengatakan dia menggunakan me.alih-alih this->. Karena tidak ada kebutuhan untuk this->tidak perlu me.dan dengan demikian tidak perlu untuk makro.
Martin York
11
@LokiAstari: Tidak ada dalam pertanyaan yang bahkan mengisyaratkan OP bertanya-tanya apakah this->"diperlukan". Faktanya, OP mengatakan bahwa dia menggunakan this->terlepas dari kenyataan bahwa itu tidak perlu. Pertanyaannya adalah apakah me.harus digunakan sebagai pengganti this-> , yang jawaban ini tidak benar-benar menjawab.
Mehrdad
4
@Mehrdad: Tapi hanya menempatkan ya atau tidak membuat jawaban yang sangat membosankan. Dengan demikian penjelasan biasanya cukup berguna dalam menjelaskan bagaimana jawaban itu dicapai (dikuratori oleh Bagaimana menjawab ). Kesimpulan tidak boleh digunakan karena OP memiliki sikap yang salah untuk memulai dengan menggunakan thisdan oleh karena itu diperlukan diskusi untuk mencapai kesimpulan yang sepenuhnya seimbang.
Martin York
1
+1 untuk menjelaskan mengapa, alih-alih hanya mengatakan "Tidak, ini praktik yang buruk."
user253751
42

Jadi, Anda ingin membuat bahasa baru. Kemudian lakukan, dan jangan melumpuhkan C ++.

Ada beberapa alasan untuk tidak melakukannya:

  1. Setiap standar pengkodean normal akan menyarankan untuk menghindari makro ( inilah sebabnya )
  2. Lebih sulit untuk mempertahankan kode dengan makro seperti itu. Semua orang pemrograman di C ++ tahu apa thisitu, dan dengan menambahkan makro seperti itu, Anda sebenarnya menambahkan kata kunci baru. Bagaimana jika setiap orang memperkenalkan sesuatu yang mereka sukai? Seperti apa kode itu?
  3. Anda tidak boleh menggunakan (*this).atau this->sama sekali, kecuali dalam beberapa kasus khusus (lihat jawaban ini dan cari "ini->")

Kode Anda tidak berbeda dari #define R returnyang saya lihat di kode aktual. Alasan? Kurang mengetik!


Akan sedikit topik, tapi di sini saya akan memperluas pada poin 3 (jangan gunakan (*this).atau this->di kelas).

Pertama-tama, (*this).atau this->digunakan untuk mengakses variabel anggota atau fungsi objek. Menggunakannya tidak ada artinya dan berarti lebih banyak mengetik. Juga, membaca kode seperti itu lebih sulit, karena ada lebih banyak teks. Itu berarti pemeliharaan lebih sulit.

Jadi, kasus apa yang harus Anda gunakan this->?

(a) Pilihan nama argumen yang disayangkan.

Dalam contoh ini, this->diperlukan, karena argumen memiliki nama yang sama dengan variabel anggota:

struct A {
  int v;
  void foo( int v ) {
    this->v =v;
  }
};

(B) Ketika berhadapan dengan template dan warisan (lihat ini )

Contoh ini akan gagal dikompilasi, karena kompiler tidak tahu variabel mana yang dinamai vuntuk diakses.

template< typename T >
struct A {
  A(const T& vValue):v(vValue){}

  T v;
};

template< typename T >
struct B : A<T>
{
    B(const T& vValue):A<T>(vValue){}

    void foo( const T & newV ) {
      v = newV;
    }
};
BЈовић
sumber
1
"Jadi, kamu ingin membuat bahasa baru. Lalu lakukan itu, dan jangan melumpuhkan c ++." - Saya tidak setuju. Kekuatan utama C dan C ++ adalah fleksibilitasnya. OP tidak melumpuhkan C ++, hanya memanfaatkan fleksibilitasnya dengan cara tertentu untuk membuatnya lebih mudah baginya untuk kode.
user253751
2
@immibis Benar. Apa yang lebih mudah baginya, lebih sulit bagi orang lain. Ketika Anda bekerja dalam tim, memasukkan omong kosong seperti itu dalam kode tidak akan membuat Anda sangat disukai.
BЈовић
2
Jawaban Anda tidak berbeda dengan "mendefinisikan jahat".
Tn. Lister
7
@ Tuan Jawaban saya adalah "mendefinisikan bodoh itu jahat". Makro dalam pertanyaan itu bodoh untuk digunakan, dan seperti yang saya tunjukkan, tidak diperlukan sama sekali. Kode ini baik dan bahkan lebih baik tanpa *this.danthis->
15овић
1
@Mehrdad Apakah orang masih menambahkan awalan dan sufiks ke variabel anggota? Saya pikir itu "diperbaiki" dengan buku-buku seperti Clean Code . this->berguna seperti autopada pre-c ++ 11. Dengan kata lain, itu hanya meningkatkan noise kode.
BЈовић
26

Saya sarankan untuk tidak melakukan ini. Ini memberi pembaca yang tidak akrab dengan makro Anda " WTF " besar setiap kali dia melihat ini. Kode tidak menjadi lebih mudah dibaca ketika menemukan "konvensi baru" di atas konvensi yang diterima secara umum tanpa kebutuhan nyata.

menggunakan ini-> di mana-mana terlalu berisik dan jelek

Itu mungkin tampak begitu bagi Anda, mungkin karena Anda melakukan banyak pemrograman dalam bahasa menggunakan kata kunci me(Visual Basic, saya kira?). Tapi sebenarnya itu hanya masalah menjadi terbiasa - this->cukup singkat, dan saya pikir sebagian besar programmer C ++ yang berpengalaman akan tidak setuju dengan pendapat Anda. Dan dalam kasus di atas, baik penggunaan this->atau penggunaan metidak sesuai - Anda mendapatkan jumlah terkecil dari kekacauan dengan meninggalkan kata kunci tersebut ketika mengakses data anggota di dalam fungsi anggota.

Jika Anda ingin variabel anggota pribadi Anda dibedakan dari variabel lokal, tambahkan tautan sesuatu m_sebagai awalan, atau garis bawah sebagai akhiran untuk variabel tersebut (tetapi seperti yang Anda lihat di sini , bahkan konvensi ini "terlalu berisik" bagi banyak orang).

Doc Brown
sumber
12
_harus suffixed ; sebagai awalan dicadangkan untuk simbol internal perpustakaan standar dan ekstensi vendor.
Jan Hudec
4
@JanHudec Hanya jika dimulai dengan __(dua garis bawah) atau garis bawah diikuti dengan huruf kapital. Satu garis bawah diikuti oleh huruf kecil baik-baik saja, asalkan tidak di namespace global.
Eric Finn
1
@ EricFinn: Saya menggabungkan dua aturan menjadi satu. Dua garis bawah atau garis bawah diikuti dengan huruf kapital untuk simbol internal dan garis bawah tunggal diikuti oleh huruf kecil untuk ekstensi sistem-spesifik. Aplikasi tidak boleh menggunakan keduanya.
Jan Hudec
@JanHudec Tidak mengetahui aturan untuk ekstensi khusus sistem. Saya akan meninggalkan komentar saya sebelumnya untuk memberikan konteks untuk komentar Anda.
Eric Finn
2
@ JanHudec: Huruf kecil untuk ekstensi spesifik sistem? Bisakah Anda memposting referensi ke bagian standar C ++ yang menunjukkan ini?
Mehrdad
18

Tolong jangan lakukan itu! Saya mencoba untuk mengatasi basis kode besar di mana makro semua tempat untuk menyimpan mengetik. Hal buruk tentang mendefinisikan ulang ini bagi saya adalah bahwa preprocessor akan menggantikannya di mana-mana bahkan di mana ini tidak dalam ruang lingkup / tidak berlaku, misalnya fungsi yang berdiri sendiri, rekan rekan Anda mungkin memiliki variabel lokal memanggil saya di tempat lain .. (s) ia tidak akan senang men-debug ... Anda akhirnya memiliki makro yang tidak dapat Anda gunakan di semua lingkup.

truschival
sumber
6

TIDAK!

Bayangkan saja kebingungan yang akan terjadi jika seseorang # sundulan itu, tidak tahu trik Anda, dan di tempat lain dalam file mereka mereka memiliki variabel atau fungsi yang disebut "saya". Mereka akan sangat bingung dengan pesan kesalahan apa pun yang tidak dapat dicetak yang akan dicetak.

Larry Gritz
sumber
Dalam praktiknya, mereka cenderung mengarahkan "saya" dengan IDE mereka dan melihat definisinya.
user253751
2
@immibis: Dalam praktiknya, mereka juga cenderung mengatakan sesuatu seperti "siapa yang menulis omong kosong ini?". : P
cHao
@immibis: sebagian besar pembuat kode teratas yang saya gunakan tidak menggunakan mouse - terlalu lambat.
JBRWilkinson
Memang: mendorong ini di header adalah masalah sebenarnya. Jika Anda menggunakannya dalam file cpp Anda, saya tidak melihat masalah sama sekali. Jika kita memiliki pragma push sebagai standar, saya akan menyarankan cara melakukan ini di header, tetapi kita tidak melakukannya. Ulangi setelah saya. # definisi bersifat global.
Joshua