Câu trả lời:
Nhiều di sản (viết tắt là MI) có mùi , có nghĩa là thông thường , nó được thực hiện vì lý do xấu, và nó sẽ thổi ngược lại vào mặt của người bảo trì.
Điều này đúng với thừa kế, và do đó, nó thậm chí còn đúng hơn đối với nhiều kế thừa.
Có phải đối tượng của bạn thực sự cần phải kế thừa từ người khác? A Car
không cần kế thừa từ một Engine
để làm việc, cũng không phải từ a Wheel
. A Car
có một Engine
và bốn Wheel
.
Nếu bạn sử dụng nhiều kế thừa để giải quyết các vấn đề này thay vì thành phần, thì bạn đã làm sai điều gì đó.
Thông thường, bạn có một lớp A
, sau đó B
và C
cả hai đều kế thừa từ A
. Và (đừng hỏi tôi tại sao) sau đó ai đó quyết định rằng D
phải thừa hưởng cả từ B
vàC
.
Tôi đã gặp loại vấn đề này hai lần trong 8 năm, và thật thú vị khi thấy vì:
D
không nên thừa hưởng từ cả hai B
và C
), bởi vì đây là kiến trúc tồi (trên thực tế, hoàn toàn C
không nên tồn tại ...)A
đã có mặt hai lần trong lớp cháu của nó D
, và do đó, cập nhật một trường cha mẹ A::field
có nghĩa là cập nhật hai lần (thông qua B::field
và C::field
), hoặc có gì đó âm thầm bị lỗi và sụp đổ, sau đó (một con trỏ mới B::field
và xóa C::field
...)Sử dụng từ khóa ảo trong C ++ để đủ điều kiện thừa kế sẽ tránh bố cục kép được mô tả ở trên nếu đây không phải là điều bạn muốn, nhưng dù sao, theo kinh nghiệm của tôi, có lẽ bạn đã làm sai ...
Trong hệ thống phân cấp Đối tượng, bạn nên cố gắng giữ cấu trúc phân cấp dưới dạng Cây (một nút có MỘT cha mẹ), không phải dưới dạng biểu đồ.
Vấn đề thực sự với Diamond of Dread trong C ++ ( giả sử thiết kế là âm thanh - hãy xem lại mã của bạn! ), Đó là bạn cần đưa ra lựa chọn :
A
tồn tại hai lần trong bố cục của bạn không, và nó có nghĩa là gì? Nếu có, thì bằng mọi cách hãy thừa hưởng từ nó hai lần.Sự lựa chọn này là vấn đề cố hữu và trong C ++, không giống như các ngôn ngữ khác, bạn thực sự có thể làm điều đó mà không cần giáo điều buộc thiết kế của bạn ở cấp độ ngôn ngữ.
Nhưng giống như tất cả các quyền hạn, với sức mạnh đó có trách nhiệm: Hãy xem xét thiết kế của bạn.
Nhiều kế thừa của 0 hoặc một lớp cụ thể và không hoặc nhiều giao diện thường được chấp nhận, bởi vì bạn sẽ không gặp phải Diamond of Dread được mô tả ở trên. Trong thực tế, đây là cách mọi thứ được thực hiện trong Java.
Thông thường, ý của bạn là gì khi C thừa hưởng từ A
và B
người dùng có thể sử dụng C
như thể nó là một A
, và / hoặc như thể nó là một B
.
Trong C ++, giao diện là một lớp trừu tượng có:
Đa kế thừa từ 0 đến một đối tượng thực và không hoặc nhiều giao diện không được coi là "có mùi" (ít nhất, không nhiều như vậy).
Đầu tiên, mẫu NVI có thể được sử dụng để tạo giao diện, bởi vì tiêu chí thực sự là không có trạng thái (tức là không có biến thành viên, ngoại trừ this
). Quan điểm của giao diện trừu tượng của bạn là xuất bản hợp đồng ("bạn có thể gọi tôi theo cách này và theo cách này"), không hơn, không kém. Giới hạn của việc chỉ có phương pháp ảo trừu tượng nên là một lựa chọn thiết kế, không phải là nghĩa vụ.
Thứ hai, trong C ++, nó có ý nghĩa để kế thừa hầu như từ các giao diện trừu tượng, (ngay cả với chi phí / chỉ định bổ sung). Nếu bạn không và kế thừa giao diện xuất hiện nhiều lần trong hệ thống phân cấp của bạn, thì bạn sẽ có sự mơ hồ.
Thứ ba, định hướng đối tượng là tuyệt vời, nhưng nó không phải là Sự thật duy nhất ngoài TM trong C ++. Sử dụng các công cụ phù hợp và luôn nhớ rằng bạn có các mô hình khác trong C ++ cung cấp các loại giải pháp khác nhau.
Thỉnh thoảng đúng.
Thông thường, bạn C
lớp được kế thừa từ A
và B
và A
và B
hai đối tượng liên quan (tức là không có trong hệ thống cấp bậc tương tự, không có gì chung, khái niệm khác nhau, vv).
Ví dụ: bạn có thể có một hệ thống Nodes
với các tọa độ X, Y, Z, có thể thực hiện nhiều phép tính hình học (có thể là một điểm, một phần của các đối tượng hình học) và mỗi Node là một Tác nhân tự động, có thể giao tiếp với các tác nhân khác.
Có lẽ bạn đã có quyền truy cập vào hai thư viện, mỗi thư viện có không gian tên riêng (một lý do khác để sử dụng không gian tên ... Nhưng bạn sử dụng không gian tên, phải không?), Một người geo
và người kiaai
Vì vậy, bạn có own::Node
nguồn gốc của riêng bạn cả từ ai::Agent
và geo::Point
.
Đây là lúc bạn nên tự hỏi mình rằng bạn không nên sử dụng bố cục thay thế. Nếu own::Node
thực sự thực sự là cả a ai::Agent
và a geo::Point
, thì thành phần sẽ không làm được.
Sau đó, bạn sẽ cần nhiều kế thừa, own::Node
giao tiếp với các đại lý khác theo vị trí của họ trong không gian 3D.
(Bạn sẽ lưu ý rằng ai::Agent
và geo::Point
hoàn toàn, hoàn toàn, KHÔNG GIỚI HẠN ... Điều này làm giảm đáng kể nguy cơ đa thừa kế)
Có những trường hợp khác:
this
)Đôi khi bạn có thể sử dụng thành phần, và đôi khi MI là tốt hơn. Vấn đề là: Bạn có một sự lựa chọn. Làm điều đó có trách nhiệm (và xem lại mã của bạn).
Hầu hết thời gian, theo kinh nghiệm của tôi, không. MI không phải là công cụ phù hợp, ngay cả khi nó có vẻ hoạt động, bởi vì nó có thể được sử dụng bởi những kẻ lười biếng để chồng các tính năng lại với nhau mà không nhận ra hậu quả (như tạo Car
cả hai Engine
và a Wheel
).
Nhưng đôi khi, có. Và tại thời điểm đó, không có gì sẽ hoạt động tốt hơn MI.
Nhưng vì MI có mùi, hãy chuẩn bị để bảo vệ kiến trúc của bạn trong các bài đánh giá mã (và bảo vệ nó là một điều tốt, bởi vì nếu bạn không thể bảo vệ nó, thì bạn không nên làm điều đó).
Từ một cuộc phỏng vấn với Bjarne Stroustrup :
Mọi người hoàn toàn nói chính xác rằng bạn không cần nhiều thừa kế, bởi vì bất cứ điều gì bạn có thể làm với nhiều thừa kế bạn cũng có thể làm với một thừa kế duy nhất. Bạn chỉ cần sử dụng thủ thuật đoàn tôi đã đề cập. Hơn nữa, bạn không cần bất kỳ sự thừa kế nào cả, bởi vì bất kỳ điều gì bạn làm với một thừa kế duy nhất bạn cũng có thể làm mà không cần thừa kế bằng cách chuyển tiếp qua một lớp. Trên thực tế, bạn cũng không cần bất kỳ lớp nào, bởi vì bạn có thể làm tất cả với con trỏ và cấu trúc dữ liệu. Nhưng tại sao bạn lại muốn làm điều đó? Khi nào thuận tiện để sử dụng các cơ sở ngôn ngữ? Khi nào bạn thích một cách giải quyết? Tôi đã thấy các trường hợp trong đó nhiều kế thừa là hữu ích và thậm chí tôi đã thấy các trường hợp trong đó nhiều kế thừa khá phức tạp là hữu ích. Nói chung, tôi thích sử dụng các phương tiện được cung cấp bởi ngôn ngữ để thực hiện các giải pháp thay thế
const
- Tôi đã phải viết các cách giải quyết khó hiểu (thường sử dụng giao diện và thành phần) khi một lớp thực sự cần thiết để có các biến thể có thể thay đổi và bất biến. Tuy nhiên, tôi chưa bao giờ một lần bỏ lỡ đa kế thừa, và chưa bao giờ cảm thấy rằng tôi đã phải viết một workaround do thiếu tính năng này. Đó là sự khác biệt. Trong mọi trường hợp tôi từng thấy, không sử dụng MI là lựa chọn thiết kế tốt hơn, không phải là cách giải quyết.
Không có lý do để tránh nó và nó có thể rất hữu ích trong các tình huống. Bạn cần phải nhận thức được các vấn đề tiềm năng mặc dù.
Người lớn nhất là viên kim cương của cái chết:
class GrandParent;
class Parent1 : public GrandParent;
class Parent2 : public GrandParent;
class Child : public Parent1, public Parent2;
Bây giờ bạn có hai "bản sao" của GrandParent trong Child.
C ++ đã nghĩ về điều này mặc dù và cho phép bạn thực hiện kế thừa ảo để khắc phục các vấn đề.
class GrandParent;
class Parent1 : public virtual GrandParent;
class Parent2 : public virtual GrandParent;
class Child : public Parent1, public Parent2;
Luôn xem lại thiết kế của bạn, đảm bảo bạn không sử dụng tính kế thừa để tiết kiệm khi sử dụng lại dữ liệu. Nếu bạn có thể đại diện cho điều tương tự với thành phần (và thông thường bạn có thể) thì đây là một cách tiếp cận tốt hơn nhiều.
GrandParent
trong Child
. Có một nỗi sợ MI, bởi vì mọi người chỉ nghĩ rằng họ có thể không hiểu các quy tắc ngôn ngữ. Nhưng bất cứ ai không thể có được các quy tắc đơn giản này cũng không thể viết một chương trình không tầm thường.
Xem w: Đa kế thừa .
Nhiều kế thừa đã nhận được sự chỉ trích và như vậy, không được thực hiện bằng nhiều ngôn ngữ. Các bài phê bình bao gồm:
- Độ phức tạp tăng
- Sự mơ hồ ngữ nghĩa thường được tóm tắt là vấn đề kim cương .
- Không thể kế thừa một cách rõ ràng nhiều lần từ một lớp
- Thứ tự kế thừa thay đổi ngữ nghĩa lớp.
Nhiều kế thừa trong các ngôn ngữ với các hàm tạo kiểu C ++ / Java làm trầm trọng thêm vấn đề kế thừa của các hàm tạo và chuỗi hàm tạo, do đó tạo ra các vấn đề về bảo trì và mở rộng trong các ngôn ngữ này. Các đối tượng trong các mối quan hệ thừa kế với các phương thức xây dựng rất khác nhau rất khó thực hiện theo mô hình chuỗi xây dựng.
Cách hiện đại để giải quyết điều này để sử dụng giao diện (lớp trừu tượng thuần túy) như giao diện COM và Java.
Tôi có thể làm những thứ khác thay thế cho điều này?
Vâng, bạn có thể. Tôi sẽ ăn cắp từ GoF .
Kế thừa công khai là mối quan hệ IS-A và đôi khi một lớp sẽ là một loại của một số lớp khác nhau và đôi khi điều quan trọng là phải phản ánh điều này.
"Mixins" đôi khi cũng hữu ích. Chúng thường là các lớp nhỏ, thường không kế thừa từ bất cứ thứ gì, cung cấp chức năng hữu ích.
Miễn là hệ thống phân cấp thừa kế khá nông (vì nó hầu như luôn luôn như vậy) và được quản lý tốt, bạn sẽ không có được quyền thừa kế kim cương đáng sợ. Kim cương không phải là vấn đề với tất cả các ngôn ngữ sử dụng nhiều tính kế thừa, nhưng cách xử lý của C ++ về nó thường rất khó xử và đôi khi khó hiểu.
Mặc dù tôi gặp phải trường hợp nhiều thừa kế rất tiện dụng, nhưng chúng thực sự khá hiếm. Điều này có thể là do tôi thích sử dụng các phương pháp thiết kế khác khi tôi không thực sự cần nhiều kế thừa. Tôi thích tránh các cấu trúc ngôn ngữ khó hiểu và thật dễ dàng để xây dựng các trường hợp thừa kế trong đó bạn phải đọc hướng dẫn thực sự tốt để tìm hiểu điều gì đang xảy ra.
Bạn không nên "tránh" nhiều kế thừa nhưng bạn nên chú ý đến các vấn đề có thể phát sinh, chẳng hạn như 'vấn đề kim cương' ( http://en.wikipedia.org/wiki/Diamond_probols ) và chăm sóc sức mạnh cho bạn , như bạn nên với tất cả các quyền hạn.
Có nguy cơ nhận được một chút trừu tượng, tôi thấy nó sáng tỏ khi nghĩ về sự kế thừa trong khung lý thuyết thể loại.
Nếu chúng ta nghĩ về tất cả các lớp và mũi tên giữa chúng biểu thị quan hệ thừa kế, thì đại loại như thế này
A --> B
có nghĩa là class B
xuất phát từ class A
. Lưu ý rằng, đã cho
A --> B, B --> C
chúng ta nói C xuất phát từ B xuất phát từ A, do đó C cũng được cho là xuất phát từ A, do đó
A --> C
Hơn nữa, chúng tôi nói rằng đối với mọi lớp A
có A
nguồn gốc tầm thường A
, do đó mô hình thừa kế của chúng tôi đáp ứng định nghĩa của một thể loại. Trong ngôn ngữ truyền thống hơn, chúng ta có một thể loại Class
với các đối tượng tất cả các lớp và hình thái quan hệ thừa kế.
Đó là một chút thiết lập, nhưng với điều đó, hãy xem Diamond of Doom của chúng tôi:
C --> D
^ ^
| |
A --> B
Đó là một sơ đồ mờ ám, nhưng nó sẽ làm được. Vì vậy, D
kế thừa từ tất cả các A
, B
và C
. Hơn nữa, và tiến gần hơn đến việc giải quyết câu hỏi của OP, D
cũng thừa hưởng từ bất kỳ siêu lớp nào A
. Chúng ta có thể vẽ sơ đồ
C --> D --> R
^ ^
| |
A --> B
^
|
Q
Bây giờ, các vấn đề liên quan đến Kim cương tử thần ở đây là khi C
và B
chia sẻ một số tên thuộc tính / phương thức và mọi thứ trở nên mơ hồ; tuy nhiên, nếu chúng ta di chuyển bất kỳ hành vi chia sẻ nào vào A
thì sự mơ hồ sẽ biến mất.
Đặt trong các thuật ngữ phân loại, chúng tôi muốn A
, B
và C
để được nếu B
và C
kế thừa từ Q
đó A
có thể được viết lại như là lớp con của Q
. Điều này làm cho A
một cái gì đó được gọi là đẩy ra .
Ngoài ra còn có một cấu trúc đối xứng D
được gọi là pullback . Đây về cơ bản là lớp hữu ích chung nhất mà bạn có thể xây dựng kế thừa từ cả hai B
và C
. Đó là, nếu bạn có bất kỳ lớp nào khác được R
thừa kế từ B
và C
, thì đó D
là một lớp R
có thể được viết lại dưới dạng lớp con của D
.
Đảm bảo rằng các mẹo về viên kim cương của bạn là pullback và đẩy cho chúng ta một cách hay để xử lý chung các vấn đề về xung đột tên hoặc bảo trì có thể phát sinh theo cách khác.
Lưu ý câu trả lời của Paercebal đã truyền cảm hứng cho điều này vì những lời khuyên của anh ta được ngụ ý bởi mô hình trên cho rằng chúng tôi làm việc trong toàn thể loại Lớp của tất cả các lớp có thể.
Tôi muốn khái quát hóa lập luận của anh ấy đến một cái gì đó cho thấy mức độ phức tạp của nhiều mối quan hệ thừa kế có thể vừa mạnh mẽ vừa không có vấn đề.
TL; DR Hãy nghĩ về các mối quan hệ thừa kế trong chương trình của bạn như là một thể loại. Sau đó, bạn có thể tránh các vấn đề của Diamond of Doom bằng cách tạo các lớp đẩy được thừa kế nhiều lần và đối xứng, tạo một lớp cha phổ biến là một pullback.
Chúng tôi sử dụng Eiffel. Chúng tôi có MI tuyệt vời. Đừng lo lắng. Không vấn đề. Dễ dàng quản lý. Có những lúc KHÔNG sử dụng MI. Tuy nhiên, nó hữu ích hơn mọi người nhận ra bởi vì họ: A) trong một ngôn ngữ nguy hiểm không quản lý tốt nó -OR- B) hài lòng với cách họ đã làm việc xung quanh MI trong nhiều năm và nhiều năm -OR- C) những lý do khác ( quá nhiều để liệt kê tôi khá chắc chắn - xem câu trả lời ở trên).
Đối với chúng tôi, sử dụng Eiffel, MI cũng tự nhiên như mọi thứ khác và một công cụ tốt khác trong hộp công cụ. Thành thật mà nói, chúng tôi khá không quan tâm rằng không ai khác đang sử dụng Eiffel. Đừng lo lắng. Chúng tôi hài lòng với những gì chúng tôi có và mời bạn có một cái nhìn.
Trong khi bạn đang tìm kiếm: Lưu ý đặc biệt về sự an toàn của Void và việc xóa bỏ hội thảo con trỏ Null. Trong khi tất cả chúng ta đang nhảy múa xung quanh MI, con trỏ của bạn đang bị lạc! :-)
Mỗi ngôn ngữ lập trình có một cách xử lý khác nhau về lập trình hướng đối tượng với những ưu và nhược điểm. Phiên bản của C ++ đặt sự nhấn mạnh vào hiệu năng và có nhược điểm đi kèm là rất dễ viết mã không hợp lệ - và điều này đúng với nhiều kế thừa. Kết quả là có một xu hướng lèo lái các lập trình viên ra khỏi tính năng này.
Những người khác đã giải quyết câu hỏi về việc thừa kế nhiều thứ không tốt cho việc gì. Nhưng chúng tôi đã thấy khá nhiều ý kiến cho rằng ít nhiều ngụ ý rằng lý do để tránh nó là vì nó không an toàn. Vâng, có và không.
Như thường đúng trong C ++, nếu bạn làm theo một hướng dẫn cơ bản, bạn có thể sử dụng nó một cách an toàn mà không phải "nhìn qua vai" liên tục. Ý tưởng chính là bạn phân biệt một loại định nghĩa lớp đặc biệt gọi là "hỗn hợp"; lớp là một hỗn hợp nếu tất cả các hàm thành viên của nó là ảo (hoặc ảo thuần). Sau đó, bạn được phép kế thừa từ một lớp chính duy nhất và bao nhiêu "hỗn hợp" tùy thích - nhưng bạn nên kế thừa các mixin với từ khóa "ảo". ví dụ
class CounterMixin {
int count;
public:
CounterMixin() : count( 0 ) {}
virtual ~CounterMixin() {}
virtual void increment() { count += 1; }
virtual int getCount() { return count; }
};
class Foo : public Bar, virtual public CounterMixin { ..... };
Đề nghị của tôi là nếu bạn có ý định sử dụng một lớp làm lớp hỗn hợp, bạn cũng áp dụng quy ước đặt tên để giúp mọi người đọc mã dễ dàng xem những gì đang xảy ra & để xác minh bạn đang chơi theo quy tắc của hướng dẫn cơ bản . Và bạn sẽ thấy nó hoạt động tốt hơn nhiều nếu các mix-in của bạn cũng có các hàm tạo mặc định, chỉ vì cách các lớp cơ sở ảo hoạt động. Và hãy nhớ làm cho tất cả các kẻ hủy diệt ảo quá.
Lưu ý rằng việc tôi sử dụng từ "hỗn hợp" ở đây không giống với lớp mẫu được tham số hóa (xem liên kết này để được giải thích tốt) nhưng tôi nghĩ đó là cách sử dụng hợp lý thuật ngữ.
Bây giờ tôi không muốn tạo ấn tượng rằng đây là cách duy nhất để sử dụng nhiều kế thừa một cách an toàn. Đó chỉ là một cách khá dễ kiểm tra.
Bạn nên sử dụng nó một cách cẩn thận, có một số trường hợp, như Vấn đề Kim cương , khi mọi thứ có thể trở nên phức tạp.
(nguồn: learncpp.com )
Printer
thậm chí không nên là một PoweredDevice
. A Printer
là để in, không phải quản lý năng lượng. Việc triển khai một máy in cụ thể có thể phải thực hiện một số quản lý nguồn, nhưng các lệnh quản lý nguồn này không được tiếp xúc trực tiếp với người dùng máy in. Tôi không thể tưởng tượng bất kỳ việc sử dụng thế giới thực này của hệ thống phân cấp này.
Sử dụng và lạm dụng quyền thừa kế.
Bài báo làm một công việc tuyệt vời để giải thích sự kế thừa, và nó nguy hiểm.
Ngoài mô hình kim cương, nhiều kế thừa có xu hướng làm cho mô hình đối tượng khó hiểu hơn, điều này làm tăng chi phí bảo trì.
Thành phần về bản chất là dễ hiểu, hiểu và giải thích. Việc viết mã có thể trở nên tẻ nhạt, nhưng một IDE tốt (đã vài năm kể từ khi tôi làm việc với Visual Studio, nhưng chắc chắn các IDE Java đều có các công cụ tự động tắt phím sáng tác tuyệt vời) sẽ giúp bạn vượt qua rào cản đó.
Ngoài ra, về mặt bảo trì, "vấn đề kim cương" cũng xuất hiện trong các trường hợp thừa kế không theo nghĩa đen. Chẳng hạn, nếu bạn có A và B và lớp C của bạn mở rộng cả hai và A có phương pháp 'makeJuice' tạo ra nước cam và bạn mở rộng điều đó để tạo ra nước cam với một vắt vôi: điều gì xảy ra khi nhà thiết kế cho ' B 'thêm phương pháp' makeJuice 'tạo ra và dòng điện? 'A' và 'B' có thể tương thích với "cha mẹ" ngay bây giờ , nhưng điều đó không có nghĩa là họ sẽ luôn như vậy!
Nhìn chung, châm ngôn của xu hướng tránh kế thừa, và đặc biệt là nhiều kế thừa, là âm thanh. Như tất cả các câu châm ngôn, đều có ngoại lệ, nhưng bạn cần chắc chắn rằng có một dấu hiệu neon màu xanh lá cây nhấp nháy chỉ vào bất kỳ trường hợp ngoại lệ nào bạn mã hóa (và huấn luyện bộ não của bạn để bất cứ khi nào bạn nhìn thấy những cây thừa kế như vậy bạn vẽ trong đèn neon màu xanh lá cây nhấp nháy của riêng bạn ký) và rằng bạn kiểm tra để đảm bảo tất cả đều có ý nghĩa mỗi lần.
what happens when the designer for 'B' adds a 'makeJuice' method which generates and electrical current?
Uhhh, bạn nhận được một lỗi biên dịch tất nhiên (nếu việc sử dụng là mơ hồ).
Vấn đề chính với MI của các đối tượng cụ thể là hiếm khi bạn có một đối tượng hợp pháp nên "Trở thành A VÀ là B", vì vậy hiếm khi đó là giải pháp chính xác trên cơ sở logic. Thường xuyên hơn, bạn có một đối tượng C tuân theo "C có thể hoạt động như A hoặc B", mà bạn có thể đạt được thông qua kế thừa và bố cục giao diện. Nhưng đừng nhầm lẫn - kế thừa nhiều giao diện vẫn là MI, chỉ là một tập hợp con của nó.
Đối với C ++ nói riêng, điểm yếu chính của tính năng không phải là SỰ TUYỆT VỜI thực tế của Đa kế thừa, nhưng một số cấu trúc mà nó cho phép hầu như luôn bị sai. Ví dụ: kế thừa nhiều bản sao của cùng một đối tượng như:
class B : public A, public A {};
bị dị hình B DENG ĐỊNH NGH DEA. Được dịch sang tiếng Anh đây là "B là A và A". Vì vậy, ngay cả trong ngôn ngữ của con người cũng có một sự mơ hồ nghiêm trọng. Ý bạn là "B có 2 As" hay chỉ "B là A"?. Cho phép mã bệnh lý như vậy, và tệ hơn là biến nó thành một ví dụ sử dụng, C ++ không ủng hộ khi đưa ra một trường hợp để giữ tính năng này trong các ngôn ngữ kế nhiệm.
Bạn có thể sử dụng thành phần trong sở thích để thừa kế.
Cảm giác chung là thành phần tốt hơn, và nó được thảo luận rất tốt.
The general feeling is that composition is better, and it's very well discussed.
Điều đó không có nghĩa là thành phần tốt hơn.
phải mất 4/8 byte cho mỗi lớp liên quan. (Một con trỏ này cho mỗi lớp).
Điều này có thể không bao giờ là một mối quan tâm, nhưng nếu một ngày nào đó bạn có một cấu trúc dữ liệu vi mô, nó sẽ mất hàng tỷ thời gian.