ความหลากหลายใน 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.