Как экземпляр базового класса может содержать экземпляр производного класса? - PullRequest
9 голосов
/ 10 ноября 2011

Я был программистом .Net (не могу сказать, что я программист) в течение 2 лет.Есть один вопрос, который я не могу понять годами, а именно: как экземпляр базового класса может содержать экземпляр производного класса?

Предположим, у нас есть два класса:

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

class DerivedClass :BaseClass
{
    public C propertyC;

}

Как это могло произойти:

BaseClass obj = new DerivedClass ()

Я имею в виду, что в модели памяти BaseClass нет места для вновь добавленного свойства C, так как же оно может содержать значение свойства C?

С другой стороны, как это может не произойти:

DerivedClass  obj = new BaseClass()

Я подумал, что это правильный путь, так как модель памяти DerivedClass имеет все места для BaseClass и даже больше.Но это не правда, почему?

Я знаю, что задаю действительно глупый вопрос, но кто-нибудь может дать мне более подробный ответ на этот вопрос?Было бы лучше с точки зрения памяти или компилятора.

Ответы [ 5 ]

6 голосов
/ 10 ноября 2011

Поскольку (и это понятие часто неправильно понимают), переменная, которая содержит указатель, вводится независимо от фактического конкретного типа объекта, на который он указывает.

Таким образом, когда вы пишете

BaseClass obj = new DerivedClass () 

часть, которая говорит BaseClass obj, создает новую ссылку переменную в стеке, которую компилятор понимает для хранения ссылки на что-тото есть или происходит от BaseClass.

Часть, которая читает = new DerivedClass (), фактически создает новый объект типа DerivedClass, сохраняет его в куче и сохраняет указатель на этот объект вячейка памяти, на которую указывает obj.Фактический объект в куче - это DerivedClass;это упоминается как конкретный тип объекта.

Переменная obj объявлена ​​типа BaseClass.Это не конкретный тип , это просто тип переменной , который только ограничивает компилятор от сохранения адреса в переменной, которая указывает на объект, которыйне является BaseClass или не является производным от типа BaseClass.

Это сделано для того, чтобы гарантировать, что все, что вы указали в переменной obj, независимо от того, является ли это конкретным типом BaseClassили DerivedClass, он будет иметь все методы, свойства и другие члены типа BaseClass.Он сообщает компилятору, что все применения переменной obj должны быть ограничены использованием только тех членов класса BaseClass.

4 голосов
/ 10 ноября 2011

Поскольку BaseClass является ссылочным типом, obj не является BaseClass объектом.Это ссылка на BaseClass объект.В частности, это ссылка на BaseClass часть DerivedClass.

2 голосов
/ 10 ноября 2011

Когда вы говорите это:

BaseClass obj = new DerivedClass ()

Вы НЕ говорите: «Создайте контейнер, содержащий этот объект BaseClass, а затем поместите в него этот более крупный объект DerivedClass».

Вы фактически создаете объект DerivedClass, и он создается в области памяти, достаточной для объекта DerivedClass. Платформа .NET никогда не упускает из виду тот факт, что эта вещь является именно DerivedClass, и никогда не прекращает рассматривать ее как таковую.

Однако, когда вы говорите, что хотите использовать переменную объекта BaseClass, вы просто создаете ссылку / указатель на этот объект, который уже был создан, выделен и определен, и все такое, и ваш указатель немного более расплывчатый ,

Это похоже на того парня в другом конце комнаты, рыжеволосого ирландского полутонового куриного фермера с плохими зубами и очаровательной личностью по имени Джимми, но вы просто называете его "этим чуваком там". ». Тот факт, что вы смутно описываете его, не меняет того, кем он является или какие-либо его детали, даже если ваше расплывчатое описание совершенно точно.

0 голосов
/ 31 июля 2014

Это возможно из-за того, как память выделяется для базовых и производных классов.В производном классе сначала выделяются переменные экземпляра базового класса, а затем переменные экземпляра производного класса.Когда ссылочная переменная базового класса назначается объекту производного класса, он видит ожидаемые переменные экземпляра базового класса плюс «дополнительные» переменные экземпляра производного класса.

0 голосов
/ 10 ноября 2011

Дайте точную копию скопированного ответа от того, что другой пользователь, jk, написал на точно такой же вопрос здесь, в Stackoverflow.

Если я скажу, что у меня есть собака, вы можете смело предполагать, что у меня есть собака.

Если я скажу вам, что у меня есть домашнее животное, вы не знаете, является ли это животное собакой, оно может быть кошка или даже жираф. Не зная каких-то дополнительных информация, которую вы не можете с уверенностью предположить, что у меня есть собака.

аналогично, производный объект является объектом базового класса (как его класс), поэтому может указывать на указатель базового класса. Однако база Объект класса не является производным объектом класса, поэтому не может быть назначен указатель производного класса.

(Скрип, который вы сейчас услышите, - это растяжение аналогии)

Предположим, вы хотите купить мне подарок для моего питомца.

В первом сценарии вы знаете, что это собака, вы можете купить мне поводок, все счастливы.

Во втором сценарии я не сказал вам, что мой питомец, так что если вы собирается купить мне подарок в любом случае вам нужно знать информацию, которую я не имею сказал (или просто угадай), ты купишь мне поводок, если окажется, что я действительно была собака, все счастливы.

Однако, если у меня действительно был кот, то теперь мы знаем, что вы сделали плохо предположение (приведение) и несчастный кот на поводке (ошибка времени выполнения)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...