ความหลากหลายใน C ++

คำ polymorphismหมายถึงมีหลายรูปแบบ โดยทั่วไปความหลากหลายจะเกิดขึ้นเมื่อมีลำดับชั้นของคลาสและมีความสัมพันธ์กันโดยการถ่ายทอดทางพันธุกรรม

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

พิจารณาตัวอย่างต่อไปนี้ซึ่งคลาสพื้นฐานได้รับมาจากคลาสอื่น ๆ อีกสองคลาส -

#include <iostream> 
using namespace std;
 
class Shape {
   protected:
      int width, height;
      
   public:
      Shape( int a = 0, int b = 0){
         width = a;
         height = b;
      }
      int area() {
         cout << "Parent class area :" <<endl;
         return 0;
      }
};
class Rectangle: public Shape {
   public:
      Rectangle( int a = 0, int b = 0):Shape(a, b) { }
      
      int area () { 
         cout << "Rectangle class area :" <<endl;
         return (width * height); 
      }
};

class Triangle: public Shape {
   public:
      Triangle( int a = 0, int b = 0):Shape(a, b) { }
      
      int area () { 
         cout << "Triangle class area :" <<endl;
         return (width * height / 2); 
      }
};

// Main function for the program
int main() {
   Shape *shape;
   Rectangle rec(10,7);
   Triangle  tri(10,5);

   // store the address of Rectangle
   shape = &rec;
   
   // call rectangle area.
   shape->area();

   // store the address of Triangle
   shape = &tri;
   
   // call triangle area.
   shape->area();
   
   return 0;
}

เมื่อโค้ดด้านบนถูกคอมไพล์และเรียกใช้งานโค้ดจะได้ผลลัพธ์ดังนี้ -

Parent class area :
Parent class area :

สาเหตุของเอาต์พุตที่ไม่ถูกต้องคือการเรียกใช้พื้นที่ฟังก์ชัน () ถูกตั้งค่าหนึ่งครั้งโดยคอมไพลเลอร์เป็นเวอร์ชันที่กำหนดไว้ในคลาสพื้นฐาน นี้เรียกว่าstatic resolution ของการเรียกใช้ฟังก์ชันหรือ static linkage- การเรียกใช้ฟังก์ชันได้รับการแก้ไขก่อนที่โปรแกรมจะทำงาน บางครั้งเรียกว่าearly binding เนื่องจากฟังก์ชัน area () ถูกตั้งค่าในระหว่างการคอมไพล์โปรแกรม

แต่ตอนนี้เรามาปรับเปลี่ยนเล็กน้อยในโปรแกรมของเราและนำหน้าการประกาศพื้นที่ () ในคลาส Shape ด้วยคีย์เวิร์ด virtual เพื่อให้มีลักษณะเช่นนี้ -

class Shape {
   protected:
      int width, height;
      
   public:
      Shape( int a = 0, int b = 0) {
         width = a;
         height = b;
      }
      virtual int area() {
         cout << "Parent class area :" <<endl;
         return 0;
      }
};

หลังจากการปรับเปลี่ยนเล็กน้อยนี้เมื่อโค้ดตัวอย่างก่อนหน้านี้ถูกคอมไพล์และดำเนินการโค้ดดังกล่าวจะให้ผลลัพธ์ดังนี้ -

Rectangle class area
Triangle class area

คราวนี้คอมไพเลอร์จะดูที่เนื้อหาของตัวชี้แทนที่จะเป็นประเภท ดังนั้นเนื่องจากแอดเดรสของอ็อบเจ็กต์ของคลาส tri และ rec ถูกเก็บไว้ในรูปทรง * จึงเรียกฟังก์ชัน area () ตามลำดับ

อย่างที่คุณเห็นคลาสย่อยแต่ละคลาสมีการใช้งานแยกกันสำหรับพื้นที่ฟังก์ชัน () นี่คือวิธีการpolymorphismมักใช้ คุณมีคลาสที่แตกต่างกันโดยมีฟังก์ชันชื่อเดียวกันและแม้กระทั่งพารามิเตอร์เดียวกัน แต่มีการใช้งานที่แตกต่างกัน

ฟังก์ชั่นเสมือนจริง

virtual ฟังก์ชันคือฟังก์ชันในคลาสพื้นฐานที่ประกาศโดยใช้คีย์เวิร์ด virtual. การกำหนดฟังก์ชันเสมือนในคลาสพื้นฐานด้วยเวอร์ชันอื่นในคลาสที่ได้รับจะส่งสัญญาณไปยังคอมไพเลอร์ว่าเราไม่ต้องการการเชื่อมโยงแบบคงที่สำหรับฟังก์ชันนี้

สิ่งที่เราต้องการคือการเลือกฟังก์ชันที่จะเรียก ณ จุดใดก็ได้ในโปรแกรมเพื่อให้เป็นไปตามชนิดของวัตถุที่เรียกใช้ การดำเนินการประเภทนี้เรียกว่าdynamic linkage, หรือ late binding.

ฟังก์ชั่นเสมือนจริง

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

เราสามารถเปลี่ยนพื้นที่ฟังก์ชันเสมือน () ในคลาสพื้นฐานได้ดังต่อไปนี้ -

class Shape {
   protected:
      int width, height;

   public:
      Shape(int a = 0, int b = 0) {
         width = a;
         height = b;
      }
      
      // pure virtual function
      virtual int area() = 0;
};

= 0 บอกคอมไพเลอร์ว่าฟังก์ชันไม่มีเนื้อความและเหนือฟังก์ชันเสมือนจะถูกเรียกใช้ pure virtual function.