В статье пишут: 2 байта на каждую вирт.функцию + 2 байта на деструктор (даже если он не виртуальный) + 2 байта на "не помню что". Хотя признаю с 2 кило погорячился -- при 15 классах с 5-ю - 10-ю вирт.функциями получается около 350 байт. Эти 350 байт не экономного разбазаривания оперативки. Смиритесь... Без RTTI это не решаемо...
UPD, про механизм не прав, про вызовы все верно Я больше не буду вас переубеждать, но вы просто остановитесь на минутку и попытайтесь ответить на вопрос - зачем вообще нужны виртуальные функции? зачем вообще наследоваться? А на счет того, что без RTTI это не решаемо - легко, просто храним таблицы для объектов, а не для классов. UPD храним указатель на таблицу не.. если бы все было так, как вы говорите, то это были бы бесполезные траты.
Нонче выпускники, получившие положительную оценку по Информатике в аттестате или в дипломе, и слыхом не слыхивали что такое регистр, а Фон Нейман в их представлении модный рэпер, или композитор рингтонов для мобил., а в компьютерах - все мнят себя наполеонами!
Компиляторы создают таблицы для классов, а не для объектов. А что касается примера, то я допустил ошибку. Функция будет вызвана правильная, т.к. адрес таблицы вирт.функций будет вычислен из указателя на объект. Это я перепутал с вызовом виртуальной функции из конструктора -- там вызывалась функция из предка, если вызов был в конструкторе предка, вместо вызова нужной переопределённой...
Правда есть вопрос, что за функция вызовется в следующем случае: Код (C++): void myFunc(A arg) { arg.f(); } если в качестве аргумента передать объект класса В?
я вам уже сколько раз сказал, что если это было так, то виртуальные функции и наследование были бы бесполезны. каким это образом? ведь у нас рантайм информации о типах? это я как раз писал выше, но вы ошибаетесь когда используете слово "нужный". невозможно вызвать дочернюю функцию, потому что дочернего класса еще не существует.
Это принципиально другой случай т.к. функция будет иметь не указатель, а сам объект. Наследование работает таким образом, что по ссылке и указателю на родительский класс может в действительности находиться дочерний. В данном случае будет вызван метод класса A. Но поменять поведение очень легко Код (C++): void myFunc(A &arg)
В памяти, выделенной конкретному экземпляру объекта, есть специальных два байта, которые указывают на адрес таблицы вирт.функций. А указатель на объект как раз и указывает на эту память, где среди прочих данных объекта можно найти эти два байта -- указатель на таблицу. Тут всё просто. Но это единственное, что можно узнать о классе объекта. Полноценным RTTI это не назовёшь. Вообще перед вызовом конструктора объекту выделяется необходимая память и можно считать, что объект уже создан. Конструктор сам по себе ни каких объектов не создаёт -- конструктор можно рассматривать как хук (обработчик события создания объекта), который используется для инициализации данных объекта. Да и при вызове функции будет создана копия объекта, переданного в качестве аргумента, и вот мне пока не понятно, на основе какого класса будет создана копия и чьи конструкторы копирования (если они есть) будут вызваны. Да, только есть одно "но", в моём примере объект защищён от вмешательства в него функции (т.к. в функцию будет передана копия объекта), а в Вашем нет (т.к. будет передан сам объект). Поэтому результат работы функции может быть разным.
Для защиты есть модификатор const. А передача по значению порождает новый объект, который, к стати может быть мостом к третьему общему объекту.
За это точно не скажу. В этом вопросе я мог быть не прав. В целом такой подход лучше по памяти, чем хранить таблицу в объекте. А в процессе конструирования можно менять этот адрес. А лучше вообще "зашить" его в код(конструктора и деструктора). Тогда этот адрес можно считать неизменным и оптимизация, о которой вы говорили, возможна. Нет, т.к. поля дочернего объекта не инициализованы. Вообще, так просто не делают. Для этого есть ссылки. Кроме того, вообще непонятно, нормально ли копировать такой объект. Но почти уверен что все будет относиться только к базовому классу, т.к. идет копирование только его части. Неправда. В общем случае он защищен только если реализовано глубокое копирование. А вот тут защищен Код (C++): void myFunc(const A &arg) Ваш код порождает копирование, что долго, жрет память, может привести к изменению исходного объекта. Как раз для этого и есть константные ссылки.
Вот уж расписали))) если нужна локальная копия объекта, то передавать его аргументом по значению - самое то.
А что не нормально? Да, теряется полиморфизм. Но может быть оно так и надо. Затрудняюсь представить для чего может понадобится применительно к классам с потомками.
Я бы сказал, что все сильно зависит от ситуации. Но мне никогда не приходило в голову приводить объект к типа базового класса. Пардон, в этом вопросе вы, похоже, правы. Думаю, конструкторы и деструкторы просто не используют таблицы виртуальных функций. Получается таблицы действительно не меняются
ненормально, потому что много деталей. что есть дочерний объект сильно меняет базовый, возможно даже нарушает целостность базового. тогда копирование вообще неправомерно. глубокое копирование (предназначен ли класс для копирования?) думаю, еще можно придумать