มักจะมีประโยชน์จากมุมมองการออกแบบเพื่อให้สามารถทำเครื่องหมายสิ่งต่าง ๆ ว่าไม่เปลี่ยนแปลง ในทำนองเดียวกับผู้const
เตรียมคอมไพเลอร์และระบุว่ารัฐไม่ควรเปลี่ยนfinal
สามารถใช้เพื่อระบุพฤติกรรมที่ไม่ควรเปลี่ยนลำดับชั้นการสืบทอดต่อไป
ตัวอย่าง
พิจารณาวิดีโอเกมที่ยานพาหนะนำผู้เล่นจากที่หนึ่งไปยังอีกที่หนึ่ง ยานพาหนะทุกคันควรตรวจสอบเพื่อให้แน่ใจว่าพวกเขากำลังเดินทางไปยังสถานที่ที่ถูกต้องก่อนออกเดินทาง (ตรวจสอบให้แน่ใจว่าฐานที่ตั้งนั้นไม่ถูกทำลายเช่น) เราสามารถเริ่มต้นได้โดยใช้อินเทอร์เฟซที่ไม่ใช่เสมือน (NVI) เพื่อรับประกันว่าการตรวจสอบนี้ทำโดยไม่คำนึงถึงยานพาหนะ
class Vehicle
{
public:
virtual ~Vehicle {}
bool transport(const Location& location)
{
// Mandatory check performed for all vehicle types. We could potentially
// throw or assert here instead of returning true/false depending on the
// exceptional level of the behavior (whether it is a truly exceptional
// control flow resulting from external input errors or whether it's
// simply a bug for the assert approach).
if (valid_location(location))
return travel_to(location);
// If the location is not valid, no vehicle type can go there.
return false;
}
private:
// Overridden by vehicle types. Note that private access here
// does not prevent derived, nonfriends from being able to override
// this function.
virtual bool travel_to(const Location& location) = 0;
};
ตอนนี้สมมติว่าเรามียานพาหนะที่บินได้ในเกมของเราและสิ่งที่ยานพาหนะการบินทั้งหมดต้องการและมีเหมือนกันคือพวกเขาจะต้องผ่านการตรวจสอบความปลอดภัยภายในโรงเก็บเครื่องบินก่อนที่จะบินขึ้น
ที่นี่เราสามารถใช้final
เพื่อรับประกันว่ายานพาหนะที่บินได้ทั้งหมดจะผ่านการตรวจสอบและสื่อสารความต้องการในการออกแบบของยานพาหนะที่บินได้
class FlyingVehicle: public Vehicle
{
private:
bool travel_to(const Location& location) final
{
// Mandatory check performed for all flying vehicle types.
if (safety_inspection())
return fly_to(location);
// If the safety inspection fails for a flying vehicle,
// it will not be allowed to fly to the location.
return false;
}
// Overridden by flying vehicle types.
virtual void safety_inspection() const = 0;
virtual void fly_to(const Location& location) = 0;
};
ด้วยการใช้final
วิธีนี้เราสามารถขยายความยืดหยุ่นของอินเทอร์เฟซที่ไม่ใช่เสมือนจริงได้อย่างมีประสิทธิภาพเพื่อแสดงพฤติกรรมที่เหมือนกันตามลำดับชั้นของการสืบทอด (แม้จะเป็นในภายหลัง นอกจากนี้เรายังซื้อห้องตัวเองเพื่อทำการเปลี่ยนแปลงที่สำคัญซึ่งส่งผลต่อยานพาหนะการบินทุกประเภทโดยไม่ต้องปรับเปลี่ยนการใช้ยานพาหนะการบินที่มีอยู่
final
นี่คือตัวอย่างหนึ่งเช่นการใช้ มีบริบทที่คุณจะพบว่ามันไม่สมเหตุสมผลสำหรับฟังก์ชั่นสมาชิกเสมือนที่จะถูกแทนที่ใด ๆ เพิ่มเติม - การทำเช่นนั้นอาจนำไปสู่การออกแบบที่เปราะบางและการละเมิดข้อกำหนดการออกแบบของคุณ
นั่นคือสิ่งที่final
มีประโยชน์จากมุมมองการออกแบบ / สถาปัตยกรรม
นอกจากนี้ยังมีประโยชน์จากมุมมองของเครื่องมือเพิ่มประสิทธิภาพเนื่องจากให้เครื่องมือเพิ่มประสิทธิภาพข้อมูลการออกแบบนี้ที่ช่วยให้สามารถพัฒนาการเรียกใช้ฟังก์ชันเสมือนจริง (กำจัดการส่งข้อมูลแบบไดนามิกและบ่อยครั้งมากขึ้น
คำถาม
จากความคิดเห็นที่:
ทำไมจะถึงขั้นสุดท้ายและเสมือนเคยใช้ในเวลาเดียวกัน
มันไม่ได้ทำให้ความรู้สึกของชั้นฐานที่รากของลำดับชั้นในการประกาศฟังก์ชั่นเป็นทั้งและvirtual
final
ดูเหมือนจะค่อนข้างโง่สำหรับฉันเพราะมันจะทำให้ทั้งผู้รวบรวมและผู้อ่านของมนุษย์ต้องกระโดดผ่านห่วงที่ไม่จำเป็นซึ่งสามารถหลีกเลี่ยงได้โดยเพียงแค่หลีกเลี่ยงvirtual
ทันทีในกรณีเช่นนี้ อย่างไรก็ตามคลาสย่อยสืบทอดฟังก์ชันสมาชิกเสมือนดังนี้:
struct Foo
{
virtual ~Foo() {}
virtual void f() = 0;
};
struct Bar: Foo
{
/*implicitly virtual*/ void f() final {...}
};
ในกรณีนี้ไม่ว่าจะBar::f
ใช้คำหลักเสมือนอย่างชัดเจนหรือไม่Bar::f
นั้นเป็นฟังก์ชั่นเสมือนจริง virtual
คำหลักแล้วจะกลายเป็นตัวเลือกในกรณีนี้ ดังนั้นมันอาจจะทำให้ความรู้สึกBar::f
ที่จะระบุเป็นfinal
แม้ว่ามันจะเป็นฟังก์ชั่นเสมือน ( final
สามารถเพียง แต่นำมาใช้สำหรับการทำงานเสมือน)
และบางคนอาจชอบโวหารเพื่อระบุอย่างชัดเจนว่าBar::f
เป็นเสมือนจริงเช่น:
struct Bar: Foo
{
virtual void f() final {...}
};
สำหรับฉันแล้วมันเป็นเรื่องซ้ำซ้อนที่จะใช้ทั้งสองvirtual
และตัวfinal
ระบุสำหรับฟังก์ชั่นเดียวกันในบริบทนี้ (เช่นเดียวกันvirtual
กับoverride
) แต่มันเป็นเรื่องของสไตล์ในกรณีนี้ บางคนอาจพบว่าvirtual
สื่อสารสิ่งที่มีคุณค่าที่นี่เช่นเดียวextern
กับการประกาศฟังก์ชั่นด้วยการเชื่อมโยงภายนอก (แม้ว่าจะเป็นตัวเลือกที่ไม่มีตัวระบุลิงก์อื่น ๆ )