ตัวดำเนินการมากเกินไป: ฟังก์ชันสมาชิกเทียบกับฟังก์ชันที่ไม่ใช่สมาชิก?


121

ฉันอ่านว่าโอเปอเรเตอร์โอเวอร์โหลดที่ประกาศว่าเป็นฟังก์ชันสมาชิกนั้นไม่สมมาตรเนื่องจากสามารถมีได้เพียงพารามิเตอร์เดียวและพารามิเตอร์อื่นที่ส่งผ่านโดยอัตโนมัติคือthisตัวชี้ ดังนั้นจึงไม่มีมาตรฐานที่จะเปรียบเทียบได้ ในทางกลับกันโอเปอเรเตอร์ที่โอเวอร์โหลดถูกประกาศว่า a friendเป็นแบบสมมาตรเนื่องจากเราส่งผ่านอาร์กิวเมนต์ประเภทเดียวกันสองอาร์กิวเมนต์ดังนั้นจึงสามารถเปรียบเทียบกันได้

คำถามของฉันคือเมื่อฉันยังสามารถเปรียบเทียบค่าของตัวชี้กับข้อมูลอ้างอิงได้ทำไมเพื่อนถึงชอบ? (การใช้เวอร์ชันอสมมาตรให้ผลลัพธ์เหมือนกับแบบสมมาตร) เหตุใดอัลกอริทึม STL จึงใช้เฉพาะเวอร์ชันสมมาตร


11
คำถามของคุณเกี่ยวกับตัวดำเนินการไบนารีเท่านั้น ตัวดำเนินการที่โอเวอร์โหลดทั้งหมดไม่ได้ถูก จำกัด ไว้ที่พารามิเตอร์เดียว ตัวดำเนินการ () สามารถรับพารามิเตอร์จำนวนเท่าใดก็ได้ ในทางกลับกันตัวดำเนินการ Unary จะไม่มีพารามิเตอร์ใด ๆ
Charles Salvia


4
นี่เป็นหนึ่งในหลายหัวข้อที่กล่าวถึงในC ++ FAQ: Operator overloading
Ben Voigt

คำตอบ:


148

หากคุณกำหนดผู้ประกอบการทำงานของคุณมากเกินไปเป็นฟังก์ชั่นสมาชิกแล้วเรียบเรียงแปลแสดงออกเหมือนเข้าไปs1 + s2 นั่นหมายความว่าตัวดำเนินการฟังก์ชันสมาชิกที่โอเวอร์โหลดจะถูกเรียกใช้ในตัวถูกดำเนินการตัวแรก นั่นคือการทำงานของสมาชิก!s1.operator+(s2)

แต่ถ้าตัวถูกดำเนินการตัวแรกไม่ใช่คลาสล่ะ? มีปัญหาสำคัญถ้าเราต้องการที่จะเกินการดำเนินการที่ถูกดำเนินการครั้งแรกไม่ได้เป็นประเภทระดับค่อนข้างพูดเป็น doubleคุณจึงเขียนแบบนี้ 10.0 + s2ไม่ได้ อย่างไรก็ตามคุณสามารถเขียนตัวดำเนินการฟังก์ชันสมาชิกที่โอเวอร์โหลดสำหรับนิพจน์เช่นs1 + 10.0.

เพื่อแก้ปัญหาการสั่งซื้อนี้เรากำหนดฟังก์ชันที่โอเวอร์โหลดของตัวดำเนินการไว้ว่าfriendถ้าจำเป็นต้องเข้าถึงprivateสมาชิกกำหนดให้friendเฉพาะเมื่อต้องการเข้าถึงสมาชิกส่วนตัว มิฉะนั้นเพียงแค่ทำให้ฟังก์ชันที่ไม่ใช่เพื่อนเป็นสมาชิกเพื่อปรับปรุงการห่อหุ้ม!

class Sample
{
 public:
    Sample operator + (const Sample& op2); //works with s1 + s2
    Sample operator + (double op2); //works with s1 + 10.0

   //Make it `friend` only when it needs to access private members. 
   //Otherwise simply make it **non-friend non-member** function.
    friend Sample operator + (double op1, const Sample& op2); //works with 10.0 + s2
}

อ่านสิ่งเหล่านี้:
ปัญหาเล็กน้อยในการสั่งซื้อในตัวถูกดำเนินการ
การฟังก์ชันที่ไม่ใช่สมาชิกปรับปรุงการห่อหุ้มอย่างไร


2
"ทำให้friendเฉพาะเมื่อจำเป็นต้องเข้าถึงสมาชิกส่วนตัว.. และเมื่อคุณไม่มี / เบื่อที่จะเขียน accessors ใช่ไหม
badmaash

4
@ Abhi: เลือกสิ่งที่คุณเลือก: ปรับปรุง Encapsulation เทียบกับนิสัยขี้เกียจเขียน!
Nawaz

6
@matthias ไม่ใช่ตัวดำเนินการทั้งหมดที่จะสับเปลี่ยน a/bตัวอย่างง่ายๆคือ
edA-qa mort-ora-y

3
วิธีทั่วไปในการหลีกเลี่ยงการทำให้ตัวดำเนินการที่ไม่ใช่สมาชิกของคุณต้องการfriendคือการนำไปใช้ในแง่ของตัวดำเนินการมอบหมายการดำเนินงาน (ซึ่งเกือบจะเป็นสมาชิกสาธารณะ) ตัวอย่างเช่นคุณสามารถกำหนดT T::operator+=(const T &rhs)เป็นสมาชิกแล้วกำหนดไม่ใช่สมาชิกเป็นT operator(T lhs, const T &rhs) return lhs += rhs;ควรกำหนดฟังก์ชันที่ไม่ใช่สมาชิกในเนมสเปซเดียวกับคลาส
Adrian McCarthy

2
@ricky: แต่ถ้า lhs เป็นสำเนา (ตามที่อยู่ในความคิดเห็นของฉัน) ความจริงที่ว่า lhs จะเปลี่ยนไปก็ไม่สำคัญ
Adrian McCarthy

20

ไม่จำเป็นต้องเป็นความแตกต่างระหว่างfriendการโอเวอร์โหลดของตัวดำเนินการและการโอเวอร์โหลดของตัวดำเนินการของสมาชิกเนื่องจากอยู่ระหว่างglobalการโอเวอร์โหลดของตัวดำเนินการและการโอเวอร์โหลดของตัวดำเนินการฟังก์ชันสมาชิก

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

Foo f = 100;
int x = 10;
cout << x + f;

สิ่งนี้ใช้ได้เฉพาะเมื่อมีตัวดำเนินการทั่วโลกเกินพิกัดสำหรับ

ตัวดำเนินการ Foo + (int x, const Foo & f);

โปรดทราบว่าโอเวอร์โหลดตัวดำเนินการทั่วโลกไม่จำเป็นต้องเป็นfriendฟังก์ชันเสมอไป สิ่งนี้จำเป็นก็ต่อเมื่อจำเป็นต้องเข้าถึงสมาชิกส่วนตัวของFooแต่นั่นก็ไม่ได้เป็นเช่นนั้นเสมอไป

ไม่ว่าFooจะมีเพียงตัวดำเนินการฟังก์ชันสมาชิกมากเกินไปเช่น:

class Foo
{
  ...
  Foo operator + (int x);
  ...
};

... จากนั้นเราจะสามารถมีนิพจน์ที่มีFooอินสแตนซ์ปรากฏทางด้านซ้ายของตัวดำเนินการบวกเท่านั้น


3
+1 สำหรับการสร้างความแตกต่างระหว่างฟังก์ชันของสมาชิกและฟังก์ชันที่ไม่ใช่สมาชิกมากกว่าฟังก์ชันของสมาชิกและเพื่อน ฉันเดาว่าวันนี้เราจะพูดว่า "global หรือ namespace scope"
Adrian McCarthy
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.