Mengapa bukan operator panah di C ++ hanya alias *.?

18

Dalam c ++, operator * dapat kelebihan beban, seperti dengan iterator, tetapi operator panah (->) (. *) Tidak bekerja dengan kelas yang membebani berlebihan * operator. Saya membayangkan bahwa preprocessor dapat dengan mudah mengganti semua contoh -> dengan (* kiri). Benar, dan itu akan membuat iterators lebih baik untuk diimplementasikan. apakah ada alasan praktis untuk -> berbeda, atau apakah itu hanya kekhasan bahasa / desainer?

Jakob Weisblat
sumber

Jawaban:

16

Aturan yang foo->barsama (*foo).barhanya berlaku untuk operator builtin.

Unary operator *tidak selalu memiliki semantik penunjuk pointer. Saya bisa membuat perpustakaan yang artinya transposisi matriks, nol atau lebih cocok parser, atau cukup banyak apa pun.

Itu akan membuat bahasa lebih menyusahkan jika sesuatu yang membebani unary operator *tiba-tiba akan mendapatkan yang operator ->tidak Anda minta, dengan semantik yang mungkin tidak masuk akal.

operator -> secara terpisah kelebihan beban, jadi jika Anda menginginkannya, Anda dapat membebani satu dengan upaya minimal.

Perhatikan juga bahwa kelebihan seperti itu akan memiliki beberapa sifat yang agak menarik, seperti operator ->panggilan chaining secara otomatis sampai satu di rantai mengembalikan pointer mentah. Ini cukup berguna untuk pointer cerdas dan tipe proxy lainnya.

#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
#include <string>
#include <iostream>
#include <ostream>

struct Foo
{
    boost::shared_ptr<std::string> operator -> () const
    {
        return boost::make_shared<std::string>("trololo");
    }
};

int main()
{
    Foo foo;
    std::cerr << foo->size() << std::endl;
}
Lars Viklund
sumber
Apa yang diilustrasikan oleh contoh Anda? Apakah Anda mengembalikan pointer pintar ke string dan entah bagaimana menghasilkan ukuran? Saya bingung.
Trevor Hickey
2
Ini mengilustrasikan paragraf terakhir dari jawaban saya, bagaimana menggunakan ->rantai operator sampai mendapat pointer mentah untuk sesuatu, mendereferensi dan mengakses anggota itu. Jika operator -> tidak berantai, contohnya tidak akan terbentuk karena shared_ptr bukan pointer mentah.
Lars Viklund
@LarsViklund: jawaban Anda memiliki masalah: Anda mengatakan "operator-> ... secara otomatis mem-chain panggilan operator-> hingga salah satu dalam rantai mengembalikan pointer mentah". Ini tidak benar - menggunakan A->Brantai sintaks paling banyak 1 panggilan tambahan. Apa yang sebenarnya dilakukan oleh C ++ -> sintaks biner adalah tidak memanggil objek opeartor->secara langsung - melainkan melihat pada tipe Adan memeriksa apakah itu merupakan pointer mentah. Jika kemudian ->deref dan jalankan Bitu, jika tidak memanggil objek operator->, deref hasilnya (baik menggunakan pointer mentah asli atau yang lain operator->dan kemudian dijalankan Bpada hasilnya
Guss
@ Guss: Saya tidak dapat menemukan bab dan ayat apa pun untuk klaim Anda, juga tidak mereproduksi dalam kompiler. C ++ 11 13.5.6 / 1 menunjukkan bahwa jika ada kelebihan beban yang sesuai, x->mharus ditafsirkan sebagai (x.operator->())->m. Jika LHS adalah sesuatu yang memiliki kelebihan yang sesuai operator->lagi, proses ini berulang hingga hanya ada (*x).mefek biasa dari 5.2.5 / 2.
Lars Viklund
8

"Bahasa Pemrograman C ++" menggambarkan fakta bahwa operator ini berbeda sehingga mereka dapat, tetapi juga mengatakan:

Jika Anda menyediakan lebih dari satu operator ini, mungkin bijaksana untuk memberikan kesetaraan, seperti halnya bijaksana untuk memastikan itu ++xdan x+=1memiliki efek yang sama seperti x=x+1untuk variabel sederhana xdari beberapa kelas jika ++, + =, =, dan + disediakan.

Jadi sepertinya perancang bahasa menyediakan poin kelebihan yang berbeda karena Anda mungkin ingin membebani mereka secara berbeda, daripada mengasumsikan bahwa Anda selalu ingin mereka tetap sama.


sumber
7

Sebagai aturan umum, C ++ dirancang untuk mendukung fleksibilitas, sehingga kelebihan *dan ->terpisah. Meskipun itu cukup tidak biasa untuk melakukannya, jika Anda ingin cukup buruk Anda dapat menulis kelebihan itu untuk melakukan hal-hal yang sama sekali berbeda (misalnya, mungkin masuk akal untuk bahasa spesifik domain yang diimplementasikan dalam C ++).

Yang mengatakan, iterator lakukan mendukung baik penggunaan. Pada implementasi kuno, Anda mungkin menemukan perpustakaan yang membutuhkan (*iter).whateveralih-alih iter->whatever, tetapi jika demikian, itu adalah bug dalam implementasi, bukan karakteristik bahasa. Mengingat jumlah pekerjaan yang terlibat dalam menerapkan semua kontainer standar / algoritma / iterator, tidak mengherankan bahwa beberapa rilis awal agak tidak lengkap, tetapi mereka tidak pernah benar-benar dimaksudkan seperti itu.

Jerry Coffin
sumber
Saya tidak menyadari kontainer perpustakaan standar diterapkan ->, atau itu kelebihan muatan.
Jakob Weisblat
3
C ++ 03 24.1 / 1 mensyaratkan bahwa setiap iterator (*i).myang valid harus mendukung i->mdengan semantik yang sama.
Lars Viklund