เหตุใดตัวแปรส่วนตัวจึงอธิบายไว้ในไฟล์ส่วนหัวที่สาธารณชนสามารถเข้าถึงได้


11

ตกลงดังนั้นหวังว่านี่เป็นคำถามที่เป็นอัตนัยสำหรับโปรแกรมเมอร์ แต่นี่จะไป ฉันเพิ่มพูนความรู้เกี่ยวกับภาษาและการปฏิบัติด้านวิศวกรรมซอฟต์แวร์อย่างต่อเนื่อง ... และฉันก็พบเจอกับบางสิ่งที่ไม่เหมาะสมกับฉันเลย

ใน C ++ การประกาศคลาสรวมถึงprivate:เมธอดและพารามิเตอร์ในไฟล์ส่วนหัวซึ่งในทางทฤษฎีแล้วคือสิ่งที่คุณส่งไปยังผู้ใช้เพื่อรวมหากคุณทำให้พวกเขาเป็น lib

ใน Objective-C @interfaceทำสิ่งเดียวกันโดยบังคับให้คุณแสดงรายชื่อสมาชิกส่วนตัว (อย่างน้อยก็มีวิธีรับเมธอดส่วนตัวในไฟล์การนำไปใช้งาน)

จากสิ่งที่ฉันสามารถบอก, Java และ C # ช่วยให้คุณเพื่อให้เป็นอินเตอร์เฟซ / โปรโตคอลซึ่งสามารถประกาศทุกคุณสมบัติที่สาธารณชนสามารถเข้าถึง / วิธีการและช่วยให้ coder ความสามารถในการซ่อนทุกรายละเอียดการปฏิบัติในการใช้งานแฟ้ม

ทำไม? การห่อหุ้มเป็นหนึ่งในหลักการสำคัญของ OOP เหตุใด C ++ และ Obj-C จึงขาดความสามารถพื้นฐานนี้ มีวิธีปฏิบัติที่ดีที่สุดสำหรับ Obj-C หรือ C ++ ที่ซ่อนการใช้ทั้งหมดหรือไม่?

ขอบคุณ


4
ฉันรู้สึกถึงความเจ็บปวดของคุณ. ฉันวิ่งออกไปกรีดร้องจาก C ++ ครั้งแรกที่ฉันเพิ่มฟิลด์ส่วนตัวในชั้นเรียนและต้องคอมไพล์ทุกสิ่งที่ใช้ใหม่
Larry Coleman

@ Larry ฉันไม่ได้สนใจอะไรมากเกินไป แต่ดูเหมือนว่าจะได้รับการยกย่องว่าเป็นภาษา OO ที่ยอดเยี่ยม แต่มันก็ไม่สามารถสรุปได้ว่า "ถูกต้อง"
Stephen Furlani

2
อย่าเชื่อโฆษณา มีวิธีที่ดีกว่าในการทำ OO ทั้งในค่ายแบบคงที่และแบบไดนามิก
Larry Coleman

มันเป็นภาษาที่ยอดเยี่ยมในบางวิธี แต่ไม่ใช่เพราะความสามารถของ OO ซึ่งเป็นการรับสินบนของ Simula 67 สู่ C.
David Thornley

คุณควรจะเขียนโปรแกรมภาษาซี จากนั้นคุณจะมีความเข้าใจที่ดีขึ้นว่าทำไมภาษาเหล่านี้ถึงเป็นอย่างที่เป็นอยู่รวมถึง Java C # และอื่น ๆ
Henry

คำตอบ:


6

คำถามคือคอมไพเลอร์จำเป็นต้องรู้ขนาดของวัตถุหรือไม่ ถ้าเป็นเช่นนั้นคอมไพเลอร์ต้องรู้เกี่ยวกับสมาชิกส่วนตัวเพื่อนับพวกเขา

ใน Java มีประเภทและวัตถุดั้งเดิมและวัตถุทั้งหมดได้รับการจัดสรรแยกต่างหากและตัวแปรที่มีพวกเขาเป็นตัวชี้จริง ๆ ดังนั้นเนื่องจากตัวชี้เป็นวัตถุขนาดคงที่คอมไพเลอร์จึงรู้ว่าตัวแปรมีขนาดใหญ่เพียงใดโดยไม่ทราบขนาดที่แท้จริงของวัตถุแบบแหลม คอนสตรัคจัดการทุกอย่าง

ใน C ++ เป็นไปได้ที่จะมีวัตถุที่เป็นตัวแทนในประเทศหรือบนกอง ดังนั้นคอมไพเลอร์จำเป็นต้องรู้ว่าวัตถุมีขนาดใหญ่เพียงใดเพื่อให้สามารถจัดสรรตัวแปรหรืออาร์เรย์ในเครื่องได้

บางครั้งเป็นที่พึงประสงค์ที่จะแบ่งการทำงานของคลาสออกเป็นส่วนต่อประสานสาธารณะและทุกอย่างที่เป็นส่วนตัวและนั่นคือที่มาของเทคนิค PIMPL (Pointer to IMPLementation) คลาสจะมีตัวชี้ไปยังคลาสการนำไปปฏิบัติส่วนตัว ที่.


คอมไพเลอร์ไม่สามารถค้นหาไลบรารีวัตถุเพื่อรับข้อมูลนี้ได้หรือไม่ เหตุใดข้อมูลนี้จึงไม่สามารถอ่านได้ด้วยเครื่องแทนที่จะอ่านได้โดยมนุษย์
Stephen Furlani

@Stephen: ในช่วงเวลาของการรวบรวมไม่จำเป็นต้องเป็นห้องสมุดวัตถุ เนื่องจากขนาดของออบเจ็กต์มีผลต่อโค้ดที่คอมไพล์จึงจำเป็นต้องทราบ ณ เวลารวบรวมไม่ใช่เฉพาะเวลาลิงค์ นอกจากนี้เป็นไปได้ที่อาจะกำหนดคลาส A, Bh เพื่อกำหนดคลาส B และนิยามฟังก์ชันใน A.cpp เพื่อใช้วัตถุของคลาส B และในทางกลับกัน ในกรณีนี้จำเป็นต้องรวบรวม A.cpp และ B.cpp แต่ละรายการก่อนหน้าหากใช้ขนาดวัตถุจากรหัสวัตถุ
David Thornley

ไม่สามารถเชื่อมโยงระหว่างการรวบรวมได้ ฉันยอมรับที่จะไม่ทราบรายละเอียดในระดับความลึกนั้น แต่หากส่วนต่อประสานของวัตถุนั้นมีเนื้อหาเนื้อหานั้นจะไม่สามารถแสดงเนื้อหาเดียวกันเหล่านั้นจากไลบรารีหรือส่วนประกอบที่เครื่องอ่านได้หรือไม่ จะต้องกำหนดไว้ในไฟล์ส่วนหัวที่สาธารณชนเข้าถึงได้หรือไม่ ฉันเข้าใจว่านี่เป็นส่วนหนึ่งของภาษา C ส่วนใหญ่ แต่ต้องเป็นเช่นนั้นหรือไม่
Stephen Furlani

1
@Stephen: การเชื่อมโยงสามารถทำได้ในระหว่างการรวบรวมหากมีส่วนประกอบที่เหมาะสมทั้งหมดเท่านั้น ถึงแม้ว่ามันจะเป็นกระบวนการที่ซับซ้อนที่เกี่ยวข้องกับการรวบรวมบางส่วน (ทุกอย่างยกเว้นขนาดวัตถุ), การเชื่อมโยงบางส่วน (เพื่อให้ได้ขนาดวัตถุ) จากนั้นรวบรวมและเชื่อมโยงขั้นสุดท้าย เนื่องจาก C และ C ++ เป็นภาษาที่ค่อนข้างเก่าซึ่งจะไม่เกิดขึ้น บางคนอาจออกแบบภาษาใหม่โดยไม่มีไฟล์ส่วนหัว แต่จะไม่เป็น C ++
David Thornley

14

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

เช่นถ้าคุณกำหนดคลาส

class Foo {
    public int a;
    private int b;
};

แล้วคือsizeof(Foo) sizeof(a) + sizeof(b)หากมีกลไกบางอย่างในการแยกเขตข้อมูลส่วนตัวส่วนหัวอาจมี

class Foo {
    public int a;
};

sizeof(Foo) = sizeof(a) + ???กับ

หากคุณต้องการซ่อนข้อมูลส่วนตัวให้ลองใช้ pimpl idiom ด้วย

class FooImpl;
class Foo {
    private FooImpl* impl;
}

ในส่วนหัวและคำจำกัดความFooImplเฉพาะสำหรับFooไฟล์การใช้งานของ


โอ้ ฉันไม่รู้ว่านี่เป็นกรณีนี้ นั่นเป็นเหตุผลว่าทำไมภาษาเช่น Java, C # และ Obj-C มี "Class Objects" เพื่อให้พวกเขาสามารถถามคลาสว่าวัตถุควรใหญ่ขนาดไหน?
Stephen Furlani

4
ลองใช้ pimpl ซึ่งเป็นตัวชี้ไปยังการใช้งานส่วนตัว เนื่องจากพอยน์เตอร์ของคลาสทั้งหมดมีขนาดเท่ากันคุณจึงไม่จำเป็นต้องกำหนดคลาสการนำไปใช้ให้ประกาศเฉพาะเท่านั้น
สกอตต์เวลส์

ฉันคิดว่ามันควรจะเป็นคำตอบแทนความคิดเห็น
Larry Coleman

1

ทั้งหมดนี้มาพร้อมกับตัวเลือกการออกแบบ

หากคุณต้องการซ่อนรายละเอียดการนำไปใช้ส่วนตัวของคลาส C ++ หรือ Objective-C อย่างแท้จริงคุณต้องจัดเตรียมหนึ่งอินเตอร์เฟสขึ้นไปที่คลาสนั้นรองรับ (คลาสเสมือนบริสุทธิ์ C ++, Objective-C @protocol) และ / หรือคุณสร้างคลาส สามารถสร้างตัวเองโดยการให้วิธีการคงที่จากโรงงานหรือวัตถุโรงงานคลาส

เหตุผลที่ตัวแปรส่วนตัวถูกเปิดเผยในไฟล์ส่วนหัว / การประกาศคลาส / อินเทอร์เฟซ @ คือผู้บริโภคของคลาสของคุณอาจต้องสร้างอินสแตนซ์ใหม่ของมันและในnew MyClass()หรือ[[MyClass alloc]init]ในรหัสลูกค้าต้องการคอมไพเลอร์เพื่อทำความเข้าใจว่า MyClass ใหญ่แค่ไหน วัตถุอยู่ในลำดับที่จะทำการจัดสรร

Java และ C # ยังมีตัวแปรส่วนตัวของพวกเขาที่มีรายละเอียดในชั้นเรียน - พวกมันไม่มีข้อยกเว้นในเรื่องนี้ แต่ IMO กระบวนทัศน์ของส่วนต่อประสานนั้นมีอยู่ทั่วไปในภาษาเหล่านั้น คุณอาจไม่มีซอร์สโค้ดในแต่ละกรณี แต่มีข้อมูลเมตาเพียงพอในคอมไพล์ / ไบต์รหัสเพื่ออนุมานข้อมูลนี้ เนื่องจาก C ++ และ Objective-C ไม่มีข้อมูลเมตานี้ตัวเลือกเดียวคือรายละเอียดที่แท้จริงของอินเทอร์เฟซคลาส / @ ในโลก C ++ COM คุณจะไม่เปิดเผยตัวแปรส่วนตัวของคลาสใด ๆ แต่ยังสามารถให้ไฟล์ส่วนหัวได้ - เนื่องจากคลาสนั้นเป็นเสมือนจริง มีการลงทะเบียนวัตถุของคลาสโรงงานเพื่อสร้างอินสแตนซ์ที่แท้จริงเช่นกันและมีข้อมูลเมตาบางส่วนในรูปแบบต่างๆ

ใน C ++ และ Objective-C มันเป็นงานที่น้อยกว่าในการแจกไฟล์ส่วนหัวเมื่อเทียบกับการเขียนและการบำรุงรักษาไฟล์ / interface โปรโตคอล @ เพิ่มเติม นี่คือเหตุผลหนึ่งที่คุณเห็นการใช้งานส่วนตัวเปิดเผยบ่อยครั้ง

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

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