เหตุใดตัวดำเนินการลูกศรใน C ++ จึงไม่ใช่เพียงนามแฝงของ *


18

ใน c ++ ตัวดำเนินการ * สามารถโอเวอร์โหลดได้เช่นกับตัววนซ้ำ แต่ตัวดำเนินการลูกศร (->) (. *) ไม่ทำงานกับคลาสที่โอเวอร์โหลดตัวดำเนินการ * ฉันจินตนาการว่าตัวประมวลผลล่วงหน้าสามารถแทนที่อินสแตนซ์ทั้งหมดของ -> ด้วย (* ซ้าย). right ได้อย่างง่ายดายและนั่นจะทำให้ iterators ดีกว่าที่จะใช้ มีเหตุผลในทางปฏิบัติสำหรับ -> แตกต่างหรือว่าเป็นเพียงลักษณะเฉพาะของภาษา / นักออกแบบ?

คำตอบ:


16

กฎที่foo->barเท่ากับ(*foo).barเก็บสำหรับตัวดำเนินการ builtin เท่านั้น

เอกoperator *ไม่ได้มีความหมายของตัวชี้ที่อ้างถึงเสมอไป ฉันสามารถสร้างห้องสมุดซึ่งมันหมายถึงเมทริกซ์ขนย้ายการแยกวิเคราะห์ตรงข้ามหรือเป็นศูนย์หรือมากกว่าอะไรก็ได้

มันจะทำให้ภาษาน่ารำคาญยิ่งกว่าเดิมหากมีสิ่งใดที่เกินความเป็นเอกภาพในoperator *ทันทีที่ได้รับสิ่งที่operator ->คุณไม่ได้ขอด้วยความหมายที่อาจไม่สมเหตุสมผล

operator -> สามารถโอเวอร์โหลดได้แยกต่างหากดังนั้นหากคุณต้องการคุณสามารถโอเวอร์โหลดได้อย่างง่ายดาย

นอกจากนี้โปรดทราบว่าการโอเวอร์โหลดดังกล่าวจะมีคุณสมบัติที่ค่อนข้างน่าสนใจเช่นการผูกมัดoperator ->สายอัตโนมัติจนกระทั่งหนึ่งในห่วงโซ่ส่งกลับตัวชี้ดิบ สิ่งนี้มีประโยชน์มากสำหรับพอยน์เตอร์พอยน์เตอร์และพร็อกซีประเภทอื่น ๆ

#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;
}

ตัวอย่างของคุณอธิบายอะไร คุณกำลังส่งกลับสมาร์ทพอยน์เตอร์ไปยังสตริงและเอาท์พุทขนาดหรือไม่? ฉันสับสน
เทรเวอร์ Hickey

2
มันแสดงให้เห็นถึงย่อหน้าสุดท้ายของคำตอบของฉันวิธีการใช้->โซ่ตัวดำเนินการจนกว่าจะได้รับตัวชี้ดิบกับบางสิ่งบางอย่าง dereferencing และเข้าถึงสมาชิกของมัน หากโอเปอเรเตอร์ -> ไม่เชื่อมโยงกันตัวอย่างจะไม่ถูกต้องเนื่องจาก shared_ptr ไม่ใช่ตัวชี้แบบดิบ
Lars Viklund

@LarsViklund: คำตอบของคุณมีปัญหา: คุณบอกว่า "โอเปอเรเตอร์ -> ... เชื่อมโยงโอเปอเรเตอร์ -> โดยอัตโนมัติจนกว่าการโทรหนึ่งครั้งในเชนส่งคืนตัวชี้แบบดิบ" สิ่งนี้ไม่ถูกต้อง - การใช้A->Bเครือข่ายไวยากรณ์ที่การโทรเพิ่มเติม 1 ครั้ง สิ่งที่ C ++ -> ไวยากรณ์ไบนารีจริง ๆ แล้วไม่ได้เรียกวัตถุopeartor->โดยตรง - แต่มันจะดูที่ชนิดของAและตรวจสอบว่าเป็นตัวชี้ดิบ ถ้ามันเป็น->derefs มันและดำเนินการBกับสิ่งนั้นมิฉะนั้นมันจะเรียกวัตถุoperator->ว่า derefs ผล (ไม่ว่าจะใช้ตัวชี้ดิบพื้นเมืองหรืออื่นoperator->แล้วดำเนินการBกับผล
Guss

@Guss: ฉันไม่สามารถหาบทและข้อใด ๆ สำหรับการเรียกร้องของคุณหรือทำซ้ำในคอมไพเลอร์ C ++ 11 13.5.6 / 1 แสดงให้เห็นว่าถ้าเกินความเหมาะสมอยู่แล้วจะถูกตีความว่าเป็นx->m (x.operator->())->mหาก LHS เป็นสิ่งที่มีการโอเวอร์โหลดที่เหมาะสมoperator->อีกครั้งกระบวนการนี้จะเกิดขึ้นอีกครั้งจนกว่าจะมี(*x).mผลตามปกติเพียง5.2.5 / 2
Lars Viklund

8

"ภาษาการเขียนโปรแกรม C ++" อธิบายถึงความจริงที่ว่าตัวดำเนินการเหล่านี้แตกต่างกันเพื่อให้สามารถเป็นได้ แต่ยังกล่าวด้วย:

ถ้าคุณให้โอเปอเรเตอร์เหล่านี้มากกว่าหนึ่งตัวมันอาจเป็นการฉลาดที่จะให้ความเท่าเทียมเช่นเดียวกับที่ควรทำเพื่อให้แน่ใจว่า++xและx+=1มีผลเช่นเดียวx=x+1กับตัวแปรอย่างง่ายxของคลาสบางคลาสหาก ++, + =, =, และ + มีให้

ดังนั้นจึงดูเหมือนว่านักออกแบบภาษาที่มีให้บริการจุดเกินพิกัดที่แยกจากกันเพราะคุณอาจต้องการที่จะเกินพวกเขาต่างกันมากกว่าสมมติว่าคุณมักจะต้องการให้เป็นแบบเดียวกัน


7

ตามกฎทั่วไป C ++ ได้รับการออกแบบมาเพื่อให้มีความยืดหยุ่นดังนั้นจึงมีการโอเวอร์โหลด*และ->แยกออกจากกัน แม้ว่ามันจะค่อนข้างผิดปกติ แต่ถ้าคุณต้องการแย่พอคุณสามารถเขียนโอเวอร์โหลดเหล่านั้นเพื่อทำสิ่งที่แตกต่างอย่างสิ้นเชิง (เช่นอาจทำให้ภาษาเฉพาะโดเมนดำเนินการภายใน C ++)

ที่กล่าวว่า iterators ทำสนับสนุนการใช้งานอย่างใดอย่างหนึ่ง ในการใช้งานแบบโบราณคุณอาจพบห้องสมุดที่ต้องการ(*iter).whateverแทนที่จะเป็นiter->whateverแต่ถ้าเป็นเช่นนั้นนั่นเป็นข้อบกพร่องในการนำไปใช้ไม่ใช่ลักษณะของภาษา เมื่อพิจารณาถึงปริมาณงานที่เกี่ยวข้องในการนำมาตรฐาน / อัลกอริธึม / ตัววนซ้ำทั้งหมดมาใช้จึงไม่น่าแปลกใจที่การเผยแพร่ในช่วงแรก ๆ นั้นไม่สมบูรณ์ แต่พวกเขาไม่เคยตั้งใจจะทำเช่นนั้น


ฉันไม่ได้ตระหนักถึงการใช้คอนเทนเนอร์ของไลบรารีมาตรฐาน -> หรือเกินความสามารถ
Jakob Weisblat

3
C ++ 03 24.1 / 1 กำหนดให้ตัววนซ้ำใด ๆ ที่(*i).mถูกต้องต้องรองรับi->mด้วยความหมายเดียวกัน
Lars Viklund
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.