2011-11-10 39 views
8

Tôi đã là một coder .Net (không thể nói tôi là một lập trình viên) trong 2 năm. Có một câu hỏi mà tôi không thể hiểu trong nhiều năm, đó là làm thế nào một thể hiện của lớp cơ sở giữ một thể hiện của lớp dẫn xuất?Làm thế nào một thể hiện của lớp cơ sở giữ một thể hiện của lớp dẫn xuất?

Giả sử chúng ta có hai lớp:

class BaseClass 
{ 
    public A propertyA; 
    public B propertyB; 
} 

class DerivedClass :BaseClass 
{ 
    public C propertyC; 

} 

Làm thế nào điều này có thể xảy ra:

BaseClass obj = new DerivedClass() 

Ý tôi là, mô hình bộ nhớ của BaseClass, không có không gian cho propertyC mới được bổ sung, vậy làm thế nào có thể nó vẫn giữ giá trị của propertyC?

Ở phía bên kia, làm thế nào có thể này không thể xảy ra:

DerivedClass obj = new BaseClass() 

Tôi nghĩ đây là cách chính xác kể từ khi mô hình bộ nhớ của DerivedClass có tất cả các không gian cho BaseClass và thậm chí nhiều hơn nữa. Nhưng điều này không đúng, tại sao?

Tôi biết tôi đang đặt một câu hỏi thực sự ngu ngốc, nhưng ai đó có thể cho tôi câu trả lời chi tiết hơn về điều này? Nó sẽ tốt hơn từ quan điểm của bộ nhớ hoặc trình biên dịch.

+0

Điều này hoàn toàn giống với câu hỏi này ở đây, với câu trả lời rất hay cho câu hỏi của bạn. http://stackoverflow.com/questions/4937180/a-base-class-pointer-can-point-to-a-derived-class-object-why-is-the-vice-versa – darnir

+0

Cảm ơn tất cả vì sự xuất sắc của bạn Tôi đã có điểm :) Cảm ơn tất cả các bạn !!! ~ – NextStep

Trả lời

5

Bởi vì (và khái niệm này thường bị hiểu lầm) biến giữ con trỏ được nhập độc lập từ loại bê tông thực tế của đối tượng mà nó trỏ tới.

Vì vậy, khi bạn viết

BaseClass obj = new DerivedClass() 

phần mà nói BaseClass obj tạo ra một tham chiếu mới biến trên Stack rằng trình biên dịch hiểu để giữ một tham chiếu đến một cái gì đó có nghĩa là, hoặc Xuất phát từ BaseClass.

Phần mà đọc = new DerivedClass() thực sự tạo ra một đối tượng mới loại DerivedClass, lưu trữ nó trên Heap, và lưu trữ một con trỏ đến đối tượng đó trong vị trí nhớ mà obj điểm đến. Đối tượng thực tế trên Heap DerivedClass; điều này được gọi là loại bê tông của đối tượng.

Biến số obj được khai báo là loại BaseClass. Đây không phải là bê tông loại, nó chỉ là một loại biến, mà chỉ hạn chế các trình biên dịch từ lưu trữ một địa chỉ vào biến mà điểm để một đối tượng mà không phải là một BaseClass hay mà không có nguồn gốc từ các loại BaseClass.

này được thực hiện để đảm bảo rằng bất cứ điều gì bạn đưa vào biến obj, bất kể cho dù đó là một kiểu dữ liệu cụ của BaseClass hoặc DerivedClass, nó sẽ có tất cả các phương pháp, tài sản và các thành viên khác của các loại BaseClass. Nó cho trình biên dịch biết rằng tất cả việc sử dụng biến số obj sẽ bị hạn chế chỉ sử dụng các thành viên của lớp BaseClass.

4

BaseClass là loại tham chiếu, obj không phải là đối tượng BaseClass. Đây là tài liệu tham khảo cho đối tượng BaseClass. Cụ thể, nó là một tham chiếu đến phần BaseClass của DerivedClass.

+0

Sau khi tôi hiểu tất cả các câu trả lời khác, tôi đã nhận được điểm của bạn :) Cảm ơn bạn. – NextStep

2

Khi bạn nói điều này:

BaseClass obj = new DerivedClass() 

Bạn đang KHÔNG nói "Tạo một container chứa đối tượng BaseClass này, và sau đó nhồi nhét DerivedClass này lớn hơn đối tượng vào nó".

Bạn đang thực tế tạo đối tượng DerivedClass và nó đang được tạo trong vùng bộ nhớ đủ cho đối tượng DerivedClass. Khuôn khổ .NET không theo dõi thực tế, điều này đặc biệt là một DerivedClass, cũng không bao giờ ngừng xử lý nó như vậy. Tuy nhiên, khi bạn nói chọn sử dụng biến đối tượng BaseClass, bạn chỉ cần tạo một tham chiếu/con trỏ tới đối tượng đó đã được tạo và phân bổ và xác định và tất cả điều đó, và con trỏ của bạn chỉ cần thêm một chút nữa mơ hồ.

Nó giống như anh chàng ở đằng kia của căn phòng là một người chăn nuôi gà hơi nặng màu đỏ Ireland với răng xấu và cá tính quyến rũ tên Jimmy, nhưng bạn chỉ đề cập đến anh ta là "anh chàng đó có ". Thực tế là bạn đang mơ hồ trong việc mô tả anh ta không thay đổi những gì anh ta hay bất kỳ chi tiết nào của anh ta, mặc dù mô tả mơ hồ của bạn hoàn toàn chính xác.

+0

Điều này thực sự là một câu trả lời hài hước và dễ hiểu.Cảm ơn bạn! :) – NextStep

+0

+1 cho ví dụ! – Lazer

0

Trả lời nguyên văn được sao chép từ những gì người dùng khác, jk, đã viết trên cùng một câu hỏi ở đây trên Stackoverflow.

Nếu tôi nói với bạn rằng tôi có một con chó, bạn có thể yên tâm cho rằng tôi có con chó.

Nếu tôi nói với bạn rằng tôi có thú cưng, bạn không biết liệu động vật đó có phải là chó hay không, nó có thể là một con mèo hoặc thậm chí là một con hươu cao cổ. Nếu không biết một số thông tin bổ sung bạn không thể giả định một cách an toàn tôi có một con chó.

tương tự như một đối tượng dẫn xuất là một đối tượng lớp cơ sở (vì nó là một lớp phụ ), do đó có thể được trỏ đến bởi một con trỏ lớp cơ sở. tuy nhiên một đối tượng lớp cơ sở không phải là một đối tượng lớp dẫn xuất, do đó không thể được gán cho một con trỏ lớp dẫn xuất .

(The ọp ẹp bây giờ bạn sẽ nghe thấy là sự tương tự kéo dài)

Giả sử bây giờ bạn muốn mua cho tôi một món quà cho con vật cưng của tôi.

Trong trường hợp đầu tiên bạn biết đó là một con chó, bạn có thể mua cho tôi một dây xích, mọi người đều hạnh phúc.

Trong trường hợp thứ hai tôi chưa nói với bạn thú cưng của tôi là gì nếu bạn là sẽ mua cho tôi một món quà dù bạn cần biết thông tin tôi đã gửi nói với bạn (hoặc chỉ đoán), bạn mua cho tôi dây xích, nếu nó quay ra tôi thực sự đã có một con chó tất cả mọi người là hạnh phúc.

Tuy nhiên nếu tôi thực sự đã có một con mèo thì chúng ta bây giờ biết bạn đã thực hiện một xấu giả định (diễn viên) và có một con mèo hạnh phúc trên một dây xích (lỗi runtime)

+0

Tôi cũng nhận được quan điểm của bạn, cảm ơn bạn :) – NextStep

0

Điều này có thể vì cách bộ nhớ được phân bổ cho các lớp cơ sở và có nguồn gốc. Trong một lớp dẫn xuất, các biến cá thể của lớp cơ sở được cấp phát đầu tiên, tiếp theo là các biến cá thể của lớp dẫn xuất. Khi một biến tham chiếu lớp cơ sở được gán cho một đối tượng lớp dẫn xuất, nó sẽ thấy các biến cá thể của lớp cơ sở mà nó dự kiến ​​cộng với các biến cá thể lớp dẫn xuất "thừa".

Các vấn đề liên quan