ฉันสามารถใช้อะไรแทนตัวดำเนินการลูกศร `->` ได้


คำตอบ:


148

สองนิพจน์ต่อไปนี้เทียบเท่า:

a->b

(*a).b

(ขึ้นอยู่กับการโอเวอร์โหลดของตัวดำเนินการตามที่ Konrad กล่าวถึง แต่นั่นเป็นเรื่องผิดปกติ)


9
ปัญหาการโอเวอร์โหลดเป็นเรื่องผิดปกติน้อยกว่าที่คุณคิดไว้มาก ไม่นานมานี้ implementors STL ได้ไม่มากเกินไป->ผู้ประกอบการประเภท iterator บางอย่างเพื่อให้มี*.การใช้งาน ห้องสมุดหลายแห่งกำหนดไม่สอดคล้องกัน กลายเป็นเรื่องน่ารำคาญจริงๆเมื่อคุณทำงานกับเทมเพลตและไม่รู้ประเภทที่แม่นยำ
Konrad Rudolph

1
คุณยังสามารถทำแทนa[0].b (*a).bแต่มันจะไม่มีโครงสร้างที่เหมาะสม
Sellorio

2
Boy หลังจากหลายปีของการเขียนโปรแกรม c # การกลับไปใช้ c ++ ไม่เพียง แต่เป็นการเก็บภาษีทางปัญญาไวยากรณ์ c ++ นั้นน่าเกลียดและน่าเสียดาย ฉันรู้สึกอยากอาบน้ำหลังจากใช้มัน โปรแกรมที่เขียนด้วย c และ c ++ สนับสนุนการเขียนโปรแกรมที่ไม่ดี แอปเปิลพรียูนิกซ์พยายามทำให้ภาษาสวยเหมือนปาสคาล
ATL_DEV

@ATL_DEV ฉันจะเถียงว่าสิ่งที่น่าเกลียดจำนวนมากไม่ถือว่าเป็นสำนวนอีกต่อไป แต่น่าเสียดายที่นั่นไม่ได้หมายความว่าคุณจะไม่คุ้นเคยกับมันในฐานะโปรแกรมเมอร์ C ++ ที่ฝึกฝน นอกจากนี้เส้นทางที่ดีทางวากยสัมพันธ์มักไม่ใช่เส้นทางที่ดีทางความหมาย แต่ก็ดีขึ้นเรื่อย ๆ ไม่เลวร้ายลง แต่แล้วอีกครั้งฉันมี C ++ Stockholm Syndrome
Tim Seguine

@TimSeguine หากคุณต้องการดูโค้ดสวย ๆ ให้ดูที่เอกสารประกอบสำหรับ Macintosh ฉันคิดว่าพวกเขาคิดค้น CamelCase ชื่อตัวแปรที่สื่อความหมายได้ดีและรหัสที่จัดรูปแบบสวยงาม พวกเขาสามารถสร้างรหัส C ในภายหลังได้เกือบจะสวยงามเหมือนกับรหัส Pascal ก่อนหน้านี้
ATL_DEV

70

a->b(*a).bโดยทั่วไปคำพ้องความหมายสำหรับ วงเล็บตรงนี้จำเป็นเนื่องจากความแข็งแรงในการผูกของตัวดำเนินการ*และ.: ใช้ *a.bไม่ได้เพราะ.ผูกแน่นกว่าและถูกดำเนินการก่อน จึงเทียบเท่ากับ*(a.b).

ระวังการใช้งานมากเกินไป: เนื่องจากทั้งสองอย่าง->และ*สามารถใช้งานได้มากเกินไปความหมายของมันอาจแตกต่างกันอย่างมาก


1
โดยbinding strengthคุณหมายถึงความสำคัญของตัวดำเนินการ? ถ้าไม่ใช่อะไรคือความแตกต่างระหว่างทั้งสอง?
vishnuprasanth

1
@Vizkrig ใช่ทั้งสองคำนี้ใช้สลับกันได้ (แม้ว่า“ ลำดับความสำคัญของตัวดำเนินการ” ดูเหมือนจะบ่อยกว่ามากอย่างน้อยก็ในช่วงไม่กี่ปีที่ผ่านมา)
Konrad Rudolph

45

ภาษา C ++ กำหนดตัวดำเนินการลูกศร ( ->) เป็นคำพ้องความหมายสำหรับการ.ยกเลิกการอ้างอิงตัวชี้จากนั้นใช้-operator บนที่อยู่นั้น

ตัวอย่างเช่น:

หากคุณมีวัตถุanObjectและตัวชี้aPointer:

SomeClass anObject = new SomeClass();
SomeClass *aPointer = &anObject;

เพื่อให้สามารถใช้วิธีการวัตถุอย่างใดอย่างหนึ่งที่คุณยกเลิกการอ้างอิงตัวชี้และเรียกใช้เมธอดบนที่อยู่นั้น:

(*aPointer).method();

ซึ่งสามารถเขียนได้ด้วยตัวดำเนินการลูกศร:

aPointer->method();

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

*(aPointer.method()); // Not our intention!

คำตอบอื่น ๆ บางส่วนได้กล่าวถึงทั้งสองอย่างว่าตัวดำเนินการ C ++ สามารถโอเวอร์โหลดได้และไม่ใช่เรื่องธรรมดา


8
new SomeClass()ส่งคืนตัวชี้ ( SomeClass *) ไม่ใช่SomeClassวัตถุ และคุณเริ่มต้นด้วยการประกาศanObjectและaPointerแต่คุณกำลังใช้ในpภายหลัง
musiphil

โดยรวมแล้วคำอธิบายนี้เหมาะสมมากในทางทฤษฎีมีเพียงการเปลี่ยนแปลงของวัตถุเท่านั้นที่ทำให้สับสนเล็กน้อย แต่อธิบายกระบวนการได้ดีกว่า
Code Man

17

ใน C ++ 0x ตัวดำเนินการจะได้รับความหมายที่สองซึ่งระบุประเภทการส่งคืนของฟังก์ชันหรือนิพจน์แลมบ์ดา

auto f() -> int; // "->" means "returns ..."

1
ในทางเทคนิคการระบุว่ามันไม่ใช่ "ตัวดำเนินการ" อีกต่อไปแล้วหรือ?
Martin Ba

6
@Martin คนส่วนใหญ่ใช้คำว่า "operator" สำหรับหลาย ๆ สิ่งที่ไม่ได้ใช้กับค่าการคำนวณโดยตรง ชอบสำหรับ "::" ("ตัวดำเนินการขอบเขต") ฉันไม่รู้ว่ามุมมองของมาตรฐานในเรื่องนี้เป็นอย่างไร ในแง่นามธรรมเราสามารถมองว่า "->" เป็นตัวดำเนินการที่ทำหน้าที่แมปลำดับของประเภท (พารามิเตอร์) กับประเภทการส่งคืนเช่นตัวดำเนินการ haskell ซึ่งเขียนว่า "->" ด้วย
Johannes Schaub - litb

6
ฉันยอมแพ้! :-P
Martin Ba

2
@ JohannesSchaub-litb: ::เป็นตัวดำเนินการเหมือน.หรือ->และเรียกว่า "ตัวดำเนินการแก้ไขขอบเขต" ในมาตรฐาน
musiphil

13

ส่วนใหญ่ฉันอ่านจากขวาไปซ้ายและเรียก "in"

foo->bar->baz = qux->croak

กลายเป็น:

"baz in bar in foo กลายเป็นเสียงดังใน qux"


1

-> ใช้เมื่อเข้าถึงข้อมูลที่คุณมีตัวชี้

ตัวอย่างเช่นคุณสามารถสร้าง ptr ตัวชี้ไปยังตัวแปรประเภท int intVar ดังนี้:

int* prt = &intVar;

จากนั้นคุณสามารถใช้ฟังก์ชันเช่น foo ได้โดยการยกเลิกการอ้างอิงตัวชี้นั้นเท่านั้น - เพื่อเรียกใช้ฟังก์ชันบนตัวแปรที่ตัวชี้ชี้ไปที่แทนที่จะใช้ค่าตัวเลขของตำแหน่งหน่วยความจำของตัวแปรนั้น:

(*ptr).foo();

หากไม่มีวงเล็บตรงนี้คอมไพเลอร์จะเข้าใจสิ่งนี้*(ptr.foo())เนื่องจากความสำคัญของตัวดำเนินการซึ่งไม่ใช่สิ่งที่เราต้องการ

นี่ก็เหมือนกับการพิมพ์

ptr->foo();

ในฐานะที่เป็น->dereferences ตัวชี้นั้นและเรียกใช้ฟังก์ชันfoo()บนตัวแปรที่ตัวชี้ชี้ให้เรา

ในทำนองเดียวกันเราสามารถใช้->เพื่อเข้าถึงหรือตั้งค่าสมาชิกของคลาส:

myClass* ptr = &myClassMember;
ptr->myClassVar = 2; 

0

คุณสามารถใช้ -> เพื่อกำหนดฟังก์ชัน

auto fun() -> int
{
return 100;
}

มันไม่ใช่แลมด้า มันเป็นฟังก์ชั่นจริงๆ "->" ระบุประเภทการส่งคืนของฟังก์ชัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.