อะไรคือความแตกต่างที่สำคัญระหว่าง Inheritance และ Polymorphism?


172

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


2
อย่างใดที่เกี่ยวข้องกับคำถามนี้คือความแตกต่างได้โดยไม่ต้องรับมรดก
เอ็ดวิน Dalorzo

คำตอบ:


289

การสืบทอดคือเมื่อ 'คลาส' มาจาก 'คลาส' ที่มีอยู่ ดังนั้นถ้าคุณมีPersonชั้นเรียนแล้วคุณมีStudentคลาสที่ขยายPerson, Student สืบทอดทุกสิ่งที่Personมี มีรายละเอียดบางอย่างเกี่ยวกับตัวดัดแปลงการเข้าถึงที่คุณใส่ในฟิลด์ / วิธีการใน Person แต่นั่นเป็นแนวคิดพื้นฐาน ตัวอย่างเช่นถ้าคุณมีข้อมูลส่วนตัวบนPerson, Studentจะไม่เห็นมันเพราะส่วนตัวและเขตข้อมูลส่วนตัวจะไม่ปรากฏแก่ subclasses

ความแตกต่างเกี่ยวข้องกับวิธีที่โปรแกรมตัดสินใจว่าควรใช้วิธีใดขึ้นอยู่กับประเภทของสิ่งที่มี หากคุณมีPersonซึ่งมีreadวิธีการและคุณมีStudentซึ่งทอดตัวPersonซึ่งมีการดำเนินการของตัวเองของreadซึ่งวิธีการได้รับเรียกว่าจะถูกกำหนดให้กับคุณโดยรันไทม์ขึ้นอยู่กับว่าคุณมีหรือPerson Studentมันจะค่อนข้างยุ่งยาก แต่ถ้าคุณทำอะไรซักอย่าง

Person p = new Student();
p.read();

วิธีการอ่านของนักเรียนจะถูกเรียก นั่นคือความแตกต่างในการดำเนินการ คุณสามารถทำการมอบหมายนั้นได้เนื่องจาก a Student คือ a Personแต่ runtime นั้นฉลาดพอที่จะรู้ได้ว่าชนิดที่แท้จริงของStudentpคืออะไร

โปรดทราบว่ารายละเอียดแตกต่างกันในแต่ละภาษา คุณสามารถทำการสืบทอดใน javascript เป็นตัวอย่างได้ แต่จะแตกต่างจากวิธีการทำงานใน Java อย่างสิ้นเชิง


9
@ hvgtcodes ดังนั้นโดยสรุปความสัมพันธ์ superclass-subclass คือการสืบทอดและแนวคิดของการนำวิธีการเดียวกันมาใช้ในวิธีที่ต่างกันระหว่างคลาสแม่และคลาสย่อยและเรียกพวกเขาตามสถานการณ์คือ Polymorphism, ฉันถูกไหม?
Muhammad Raihan Muhaimin

1
@hvgotcodes แต่บอกว่าถ้าPerson's readวิธีใช้ปรับปรุงการเข้าถึงของประชาชนจะไม่Studentวัตถุจะสามารถเข้าถึงพวกเขา? แล้วStudent s = new Student();จะไม่ง่ายกว่านี้ไหม ฉันยังไม่ได้รับผลประโยชน์จากความเป็นจริงมากนัก
Scorpiorian83

1
@hvgotcodes Student s = new Student () จะใช้ได้ แต่สมมุติว่าหลังจากคุณเขียนโค้ดจำนวนมากโดยใช้ความคิดนี้และต่อมาคุณก็ตระหนักว่าคุณทำผิดพลาด บุคคลนั้นไม่ได้เป็นนักเรียน แต่เป็นครู ดังนั้นคุณสามารถเปลี่ยนจาก Person p = new Student () เป็น Person p = new Teacher () จากนั้นมันจะทำให้ชีวิตของคุณง่ายขึ้นมาก
munmunbb

คำถามของฉันที่นี่จะได้โดยการว่าทำไมคุณต้องการที่จะใช้Person p = new Student();แทนStudent p = new Student();?
PerfectContrast

@PerfectContrast ฉันคิดว่ามันมีประโยชน์เมื่อคุณต้องการให้นักเรียนคนขับอาจารย์ ฯลฯ เป็นบุคคลและคุณจัดกลุ่มพวกเขาไว้ในรายการหรืออะไรบางอย่าง ดังนั้นเมื่อคุณเรียก 'อ่าน' สำหรับทุกคนทุกคนเรียกวิธีการ 'อ่าน' ของพวกเขาเอง
savante

205

การสืบทอดหมายถึงการใช้โครงสร้างและพฤติกรรมของซูเปอร์คลาสในคลาสย่อย

ความแตกต่างหมายถึงการเปลี่ยนพฤติกรรมของคลาสสุดในคลาสย่อย


5
คำตอบนี้บอกเป็นนัย ๆ ว่าพหุนามต้องมีการรับมรดกหรือไม่?
jaco0646

6
@ jaco0646 - ในบริบทของ Java ฉันคิดอย่างนั้น (ในภาษาอื่น ๆ อาจจะไม่มากนัก) โปรดทราบว่ามีการใช้ "super class" และ "subclass" อย่างไม่ จำกัด ที่นี่ ความหลากหลายอาจหมายถึงการสืบทอดของพฤติกรรมที่ระบุ (แต่ไม่ได้นำไปใช้) ในส่วนต่อประสาน
Ted Hopp

1
@AlirezaRahmani - ฉันไม่เข้าใจความคิดเห็นของคุณ คุณหมายความว่าการสืบทอดไม่เกี่ยวข้องกับการสืบทอดทั้งคุณสมบัติและพฤติกรรม? ซึ่งจะขัดกับวิธีการที่ Java (และภาษาที่ใช้คลาสเป็นส่วนใหญ่, เชิงวัตถุ) กำหนดมรดก จากข้อกำหนดภาษา Java, §8.4.8 : "คลาส C สืบทอดมาจากซูเปอร์คลาสโดยตรงของวิธีการที่เป็นรูปธรรมทั้งหมดm(ทั้งstaticและinstance) ของซูเปอร์คลาสที่ ... " (ตามด้วยรายละเอียดเกี่ยวกับการสืบทอด) ดูเหมือนว่า "ใช้ซ้ำรหัส" กับฉัน
Ted Hopp

@TedHopp Inheritance เป็นเครื่องมือโพลีมอร์ฟิคเป็นหลัก แต่บางคนพยายามที่จะใช้มันเป็นวิธีการใช้ซ้ำ / แบ่งปันรหัส เหตุผลคือ "ดีถ้าฉันสืบทอดมาแล้วฉันจะได้รับวิธีการทั้งหมดฟรี" แต่ไม่สนใจความจริงที่ว่าทั้งสองชั้นอาจไม่มีความสัมพันธ์แบบ polymorphic
Alireza Rahmani Khalili

1
@AlirezaRahmani - ใน Java (ซึ่งเป็นสิ่งที่ OP ถามโดยเฉพาะเกี่ยวกับตามแท็ก) การสืบทอดชั้นเรียนส่วนใหญ่เกี่ยวข้องกับพฤติกรรมการสืบทอด นั่นเป็นส่วนหนึ่งของคำนิยามภาษา ความจริงที่ว่าสิ่งนี้สามารถนำไปใช้ในทางที่ผิดตามที่คุณอธิบายเป็นหนึ่งในจุดอ่อนของ Java (จุดอ่อนที่เกี่ยวข้องเกี่ยวข้องกับการประกาศคลาสเพื่อใช้อินเตอร์เฟสเพียงเพื่ออิมพอร์ตค่าคงที่ที่กำหนดในอินเตอร์เฟสในที่สุดผู้ออกแบบ Java ที่แนะนำimport staticเพื่อกำจัดการนำอินเตอร์เฟสนี้ไปใช้ในทางที่ผิด) สำหรับ pure polymorphism ใน Java เครื่องมือที่ใช้คืออินเตอร์เฟส
Ted Hopp

63

Polymorphism : ความสามารถในการรักษาวัตถุที่แตกต่างกันในลักษณะที่คล้ายกัน ตัวอย่าง: Moveยีราฟและจระเข้มีทั้งสัตว์และสัตว์สามารถ หากคุณมีตัวอย่างของAnimalแล้วคุณสามารถโทรMoveโดยไม่ต้องรู้หรือดูแลว่าเป็นสัตว์ประเภทใด

มรดก : นี่เป็นวิธีหนึ่งในการบรรลุทั้งความหลากหลายและการใช้ซ้ำรหัสในเวลาเดียวกัน

รูปแบบอื่น ๆ ของความแตกต่าง : มีวิธีอื่นในการบรรลุความหลากหลายเช่นอินเทอร์เฟซที่ให้ความแตกต่างหลากหลาย แต่ไม่มีการใช้ซ้ำรหัส (บางครั้งรหัสค่อนข้างแตกต่างกันเช่นMoveสำหรับงูจะค่อนข้างแตกต่างจากMoveสุนัขในกรณีนี้ Interface จะเป็นตัวเลือก polymorphic ที่ดีกว่าในกรณีนี้

ในความหลากหลายของภาษาไดนามิกอื่น ๆ สามารถทำได้ด้วย Duck Typing ซึ่งเป็นคลาสที่ไม่จำเป็นต้องแชร์คลาสพื้นฐานหรืออินเทอร์เฟซเดียวกันพวกเขาเพียงต้องการวิธีการที่ใช้ชื่อเดียวกัน หรือไดนามิกมากขึ้นเช่น Javascript คุณไม่จำเป็นต้องมีคลาสเลยเพียงแค่วัตถุที่มีชื่อเมธอดเดียวกันก็สามารถใช้ polymorphically ได้


17

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

นอกจากนี้ความหลากหลายที่เกี่ยวข้องกับวิธีการภาวนาในขณะที่การถ่ายทอดยังอธิบายถึงข้อมูลสมาชิก ฯลฯ


12

ใน Java ทั้งสองเกี่ยวข้องอย่างใกล้ชิด นี่เป็นเพราะ Java ใช้เทคนิคสำหรับการเรียกใช้เมธอดที่เรียกว่า "dynamic dispatch" ถ้าฉันมี

public class A {
  public void draw() { ... }
  public void spin() { ... }
}

public class B extends A {
  public void draw() { ... }
  public void bad() { ... }
}

...

A testObject = new B();

testObject.draw(); // calls B's draw, polymorphic
testObject.spin(); // calls A's spin, inherited by B
testObject.bad(); // compiler error, you are manipulating this as an A

จากนั้นเราจะเห็นว่าสืบทอด B spinจาก A. แต่เมื่อเราพยายามที่จะจัดการวัตถุราวกับว่ามันเป็นประเภทที่เรายังคงได้รับพฤติกรรม B drawสำหรับ drawพฤติกรรม polymorphic

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

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


12

ความแตกต่าง: สมมติว่าคุณทำงานให้กับ บริษัท ที่ขายปากกา ดังนั้นคุณสร้างคลาสที่ดีมากที่เรียกว่า "ปากกา" ที่จัดการทุกสิ่งที่คุณจำเป็นต้องรู้เกี่ยวกับปากกา คุณเขียนคลาสสำหรับการเรียกเก็บเงินการจัดส่งการสร้างใบแจ้งหนี้ทุกประเภทโดยใช้คลาสปากกา เจ้านายรายหนึ่งมาและพูดว่า "ข่าวดี! บริษัท กำลังเติบโตและเรากำลังขายหนังสือและซีดีอยู่ตอนนี้!" ไม่ใช่ข่าวดีเพราะตอนนี้คุณต้องเปลี่ยนทุกคลาสที่ใช้ปากกาเพื่อใช้หนังสือและซีดีด้วย แต่จะเกิดอะไรขึ้นถ้าคุณสร้างอินเทอร์เฟซที่เรียกว่า "SellableProduct" ในตอนแรกและปากกาจะใช้อินเทอร์เฟซนี้ จากนั้นคุณสามารถเขียนคลาสการจัดส่งใบแจ้งหนี้และอื่น ๆ ทั้งหมดเพื่อใช้อินเทอร์เฟซนั้นแทนปากกา ตอนนี้สิ่งที่คุณต้องทำคือสร้างคลาสใหม่ที่ชื่อว่า Book & CompactDisc ซึ่งใช้อินเทอร์เฟซ SellableProduct เนื่องจากความแตกต่างกันคลาสอื่นทั้งหมดสามารถทำงานต่อไปได้โดยไม่มีการเปลี่ยนแปลง! ทำให้รู้สึก?

ดังนั้นมันหมายถึงการใช้การสืบทอดซึ่งเป็นวิธีหนึ่งในการบรรลุความหลากหลาย

Polymorhism สามารถเกิดขึ้นได้ในคลาส / อินเตอร์เฟส แต่การสืบทอดระหว่าง 2 คลาสขึ้นไป / อินเตอร์เฟสเสมอ การสืบทอดจะสอดคล้องกับความสัมพันธ์แบบ "is-a" เสมอในขณะที่มันไม่ได้เป็นแบบ polymorphism เสมอไป (ซึ่งสามารถสอดคล้องได้ทั้งความสัมพันธ์แบบ "is-a" / "has-a"


6

การสืบทอดเป็นสิ่งที่คงที่ (คลาสหนึ่งขยายอีก) ในขณะที่ polymorphism เป็นสิ่งไดนามิก / รันไทม์ (วัตถุทำงานตามประเภทไดนามิก / รันไทม์ของมันไม่เป็นแบบคงที่ / ประกาศประเภท)

เช่น

// This assignment is possible because B extends A
A a = new B();
// polymorphic call/ access
a.foo();

-> ถึงแม้ว่าสแตติก / การประกาศของ a คือ A แต่ไดนามิก / รันไทม์ชนิดที่แท้จริงคือ B ดังนั้น a.foo () จะเรียกใช้งาน foo ตามที่กำหนดไว้ใน B ที่ไม่ได้อยู่ใน A


3

ความแตกต่างคือวิธีการแสดงพฤติกรรมทั่วไประหว่างประเภทของวัตถุที่มีลักษณะที่คล้ายกัน นอกจากนี้ยังช่วยให้การเปลี่ยนแปลงของลักษณะเหล่านั้นจะถูกสร้างขึ้นผ่านการเอาชนะ การสืบทอดเป็นวิธีที่จะทำให้เกิดความแตกต่างผ่านลำดับชั้นวัตถุที่วัตถุแสดงความสัมพันธ์และพฤติกรรมนามธรรม มันไม่ใช่วิธีเดียวที่จะทำให้เกิดความหลากหลายได้ Prototype เป็นอีกวิธีในการแสดงออกถึงความแตกต่างที่แตกต่างจากการสืบทอด JavaScript เป็นตัวอย่างของภาษาที่ใช้ต้นแบบ ฉันคิดว่ามีวิธีอื่นด้วย


3

การสืบทอดเป็นแนวคิดที่เกี่ยวข้องกับการใช้รหัสซ้ำ ตัวอย่างเช่นถ้าผมมีการพูดระดับผู้ปกครองAnimalและจะมีคุณลักษณะบางอย่างและวิธีการ (เช่นนี้พูดmakeNoise()และsleep()) และฉันจะสร้างสองชั้นเรียนของเด็กที่เรียกว่าและDog Catเนื่องจากทั้งสุนัขและแมวไปนอนในแบบเดียวกัน (ฉันจะสมมติ) มีความจำเป็นที่จะเพิ่มฟังก์ชันการทำงานมากขึ้นในsleep()วิธีในDogและCatsubclasses Animalให้โดยระดับผู้ปกครอง อย่างไรก็ตามDogเห่าและCatmeows ดังนั้นแม้ว่าAnimalชั้นเรียนอาจมีวิธีการทำเสียงสุนัขและแมวทำเสียงต่าง ๆ ที่สัมพันธ์กันและสัตว์อื่น ๆ ดังนั้นจึงมีความจำเป็นต้องกำหนดพฤติกรรมนั้นใหม่สำหรับประเภทเฉพาะของพวกเขา ดังนั้นความหมายของความแตกต่าง หวังว่านี่จะช่วยได้


3

เอกสารของออราเคิลอ้างถึงความแตกต่างอย่างแม่นยำ

การสืบทอด:คลาสสืบทอดฟิลด์และเมธอดจากซูเปอร์คลาสทั้งหมดไม่ว่าโดยตรงหรือโดยอ้อม รองสามารถแทนที่วิธีการที่จะสืบทอดหรือมันสามารถซ่อนเขตข้อมูลหรือวิธีการที่จะสืบทอด (โปรดทราบว่าการซ่อนเขตข้อมูลโดยทั่วไปคือวิธีการเขียนโปรแกรมที่ไม่ดี

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

polymorphismไม่สามารถใช้ได้กับฟิลด์

โพสต์ที่เกี่ยวข้อง:

ความแตกต่างกับการเอาชนะการบรรทุกเกินพิกัด


1

ความแตกต่างเป็นผลกระทบจากการถ่ายทอดทางพันธุกรรม มันสามารถเกิดขึ้นได้ในชั้นเรียนที่ขยายซึ่งกันและกันเท่านั้น ช่วยให้คุณสามารถเรียกวิธีการของชั้นเรียนโดยไม่ทราบประเภทที่แน่นอนของชั้นเรียน นอกจากนี้ยังมีหลายรูปแบบที่จะเกิดขึ้นในเวลาทำงาน

ตัวอย่างเช่น Java polymorphism ตัวอย่าง:

ป้อนคำอธิบายรูปภาพที่นี่

การสืบทอดทำให้คลาสที่ได้รับแบ่งใช้อินเตอร์เฟสและรหัสของคลาสพื้นฐาน มันเกิดขึ้นที่รวบรวมเวลา

ตัวอย่างเช่นคลาสทั้งหมดในแพลตฟอร์ม Java เป็นลูกหลานของวัตถุ (Oracle มารยาทภาพ):

ป้อนคำอธิบายรูปภาพที่นี่

เพื่อเรียนรู้เพิ่มเติมเกี่ยวกับการสืบทอดJavaและความหลากหลายของ Java


0

การสืบทอดคือเมื่อคลาส A สืบทอดวิธี / ฟิลด์ / ป้องกันแบบสาธารณะที่ไม่คงที่จากพ่อแม่ทั้งหมดจนถึง Object


0

ถ้าคุณใช้ JAVA มันง่ายเหมือนนี้:

ความแตกต่างคือการใช้วิธีการสืบทอด แต่ "เอาชนะ" พวกเขาที่จะทำสิ่งที่แตกต่าง (หรือเหมือนกันถ้าคุณเรียกว่าซุปเปอร์ดังนั้นในทางเทคนิคจะไม่ polymorphic)

ช่วยแก้ให้ด้วยนะถ้าฉันผิด.


0

วัตถุประสงค์หลักของpolymorphism : ในการสร้างตัวแปรอ้างอิงไปที่super classและถือsubclass object => วัตถุสามารถทำงานได้หลายอย่าง

ในการรับมรดก , subclassสืบทอดคุณสมบัติของชั้นซุปเปอร์


0

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


0

ด้วยการสืบทอดการปรับใช้จะถูกกำหนดในซูเปอร์คลาส - ดังนั้นจึงมีการสืบทอดลักษณะการทำงาน

class Animal
{
  double location;
  void move(double newLocation)
  {
    location = newLocation;
  }
}

class Dog extends Animal;

ด้วยPolymorphismการใช้งานจะถูกกำหนดในคลาสย่อย - ดังนั้นเฉพาะอินเตอร์เฟสที่สืบทอด

interface Animal
{
  void move(double newLocation);
}

class Dog implements Animal
{
  double location;
  void move(double newLocation)
  {
    location = newLocation;
  }
}

0

ความแตกต่างจะทำได้โดยการรับมรดกJavaใน

├── Animal
└── (instances)
    ├── Cat
    ├── Hamster
    ├── Lion
    └── Moose

├── interface-for-diet
   ├── Carnivore
   └── Herbivore
├── interface-for-habitat
   ├── Pet
   └── Wild

public class Animal {
    void breath() {
    };
}

public interface Carnivore {
    void loveMeat();
}

public interface Herbivore {
    void loveGreens();
}

public interface Pet {
    void liveInside();
}

public interface Wild {
    void liveOutside();
}

public class Hamster extends Animal implements Herbivore, Pet {

    @Override
    public void liveInside() {
        System.out.println("I live in a cage and my neighbor is a Gerbil");
    }

    @Override
    public void loveGreens() {
        System.out.println("I eat Carrots, Grapes, Tomatoes, and More");
    }
}

public class Cat extends Animal implements Carnivore, Pet {
    @Override
    public void liveInside() {
        System.out.println("I live in a cage and my neighbr is a Gerbil");
    }

    @Override
    public void loveMeat() {
        System.out.println("I eat Tuna, Chicken, and More");
    }
}

public class Moose extends Animal implements Herbivore, Wild {

    @Override
    public void liveOutside() {
        System.out.println("I live in the forest");
    }

    @Override
    public void loveGreens() {
        System.out.println("I eat grass");
    }
}

public class Lion extends Animal implements Carnivore, Wild {

    @Override
    public void liveOutside() {
        System.out.println("I live in the forest");
    }

    @Override
    public void loveMeat() {
        System.out.println("I eat Moose");
    }
}

Hamsterสืบทอดระดับโครงสร้างจากAnimal, HerbivoreและPetจะแสดงพฤติกรรม Polymorphicของสัตว์เลี้ยงในประเทศ

Catสืบทอดระดับโครงสร้างจากAnimal, CarnivoreและPetยังแสดงพฤติกรรม Polymorphicของสัตว์เลี้ยงในประเทศ

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