Почему чисто виртуальная функция инициализируется 0?


147

Мы всегда объявляем чисто виртуальную функцию как:

virtual void fun () = 0 ;

Т.е. оно всегда присваивается 0.

Что я понимаю, так это то, что это инициализирует запись vtable для этой функции в NULL, и любое другое значение здесь приводит к ошибке времени компиляции. Это понимание правильно или нет?


12
Обратите внимание, что vtable - это не требование языка, а просто вариант реализации для виртуальных методов. Компилятор может создать ту же абстракцию с другой реализацией (то есть без vtable и без какого-либо элемента, где 0)
David Rodríguez - dribeas

@hype Re ваш дополнительный вопрос - это то, что говорит мой ответ (и несколько других).

Просто любопытно, что произойдет, если я дам, virtual void func() = 100;
krithikaGopalakrisnan

Ответы:


161

Причина =0в том, что Бьярн Страуструп не думал, что сможет получить другое ключевое слово, такое как «чистое» прошлое сообщества C ++ во время реализации этой функции. Это описано в его книге «Дизайн и развитие C ++» , раздел 13.2.3:

Был выбран синтаксис curious = 0 ... потому что в то время я не видел шансов получить новое ключевое слово.

Он также прямо заявляет, что для этого необязательно устанавливать для записи vtable значение NULL и что это не лучший способ реализации чисто виртуальных функций.


4
Да, это просто синтаксис. Я видел много проектов, которые #define PURE = 0, и они скажут, что virtual void Foo () PURE;
i_am_jorf

79
Пожалуйста , Бог держать меня подальше от этих проектов :-)

27
Это намного хуже, чем #define BEGIN {#define END} ;-), и я иногда видел это.
Toon Krijthe

5
Такая изящная штука заставляет меня думать, что C ++ не очень совершенен. Это странно, учитывая, что он так часто используется. Я надеюсь, что язык будет лучше с течением времени.
Jokoon

19
Таким образом, другими словами, Бьярне «столкнулся с крайним сроком» и «использовал хак», чтобы преодолеть «недостаток дизайна»;) (Просто быть шутливым)
Карл

78

Как и в случае с большинством вопросов «Почему» о дизайне C ++, первое, на что стоит обратить внимание - «Дизайн и эволюция C ++ » Бьярна Страуструпа 1 :

Любопытный =0синтаксис был выбран вместо очевидной альтернативы введения нового ключевого слова pureили abstractпотому, что в то время я не видел шансов получить новое ключевое слово принятым. Если бы я предложил pure, версия 2.0 была бы поставлена ​​без абстрактных классов. Учитывая выбор между более приятным синтаксисом и абстрактными классами, я выбрал абстрактные классы. Вместо того, чтобы рисковать задержкой и нести определенные бои pure, я использовал традицию C и C ++, заключающуюся в использовании 0 для обозначения «не там». В =0синтаксических припадках с моей точкой зрения , что тело функции является инициализатором для функции также с (упрощенно, но , как правило , адекватными) ввиду множества виртуальных функций реализуются как вектор указателей на функцию. [...]

1 §13.2.3 Синтаксис


29

Раздел 9.2 стандарта C ++ дает синтаксис для членов класса. Включает в себя эту продукцию:

pure-specifier:
    = 0

В ценности нет ничего особенного. «= 0» - это всего лишь синтаксис для выражения «эта функция чисто виртуальная». Это не имеет ничего общего с инициализацией, нулевыми указателями или нулевым числовым значением, хотя сходство с этими вещами может иметь мнемоническое значение.


5
+1 за ссылку на стандарт C ++. Удивительно, что один из наилучших возможных ответов получил только один голос. Чтение стандарта должно быть самым первым шагом для решения вопросов C ++.
mloskot

7
@mloskot: может быть, потому что он не отвечает на вопрос ОП, а просто повторяет ситуацию?
просто кто-то

6
@ Просто кто-то - Он включает в себя стандартную цитату, в которой говорится, каков синтаксис объявления чисто виртуальной функции и что в синтаксисе используется чистый спецификатор = 0Что еще вы хотели бы знать? Это было бы то же самое, что спрашивать, почему тело функции заключено в {}. Ответ будет, потому что это то, что определяет синтаксис C ++.
mloskot

19

Я не уверен, есть ли за этим смысл. Это всего лишь синтаксис языка.


16

C ++ всегда избегал введения новых ключевых слов, поскольку новые зарезервированные слова ломают старые программы, которые используют эти слова для идентификаторов. Часто одной из сильных сторон языка считается то, что он максимально уважает старый код.

= 0Синтаксис , возможно , действительно был выбран , так как она напоминает установку записи в таблице виртуальной 0, но это чисто символический характер . (Большинство компиляторов присваивают такие записи vtable заглушке, которая выдает ошибку перед прерыванием программы.) Синтаксис был выбран в основном потому, что он раньше ни для чего не использовался, и он сохранил введение нового ключевого слова.


3
+1 за объяснение недостатка введения нового ключевого слова. Это полезно для понимания обоснования, но синтаксис C ++ кажется мне нелепо запутанным, и я хотел бы, чтобы они сделали его более понятным для человека - pureключевое слово было бы замечательно в моей книге. Во всяком случае, это хорошо, чтобы понять обоснование.
Кит Пинсон

@KeithPinson Если вы хотите чистое ключевое слово, вы можете #define pure = 0.
jdh8

@ jdh8: Тьфу. Просто ... Тьфу.
2016 г.

В качестве примечания, в классе с Бьярне он сказал, что он действительно хотел получить «чистое» ключевое слово в C ++ ... но он пытался получить его очень поздно в цикле, прежде чем собирался поставлять компилятор C ++ (IIRC менее двух недель). Якобы, это не получилось.
ThePhD

@ThePhD: ISTR он также говорит это где-то в D & E. (Хотя мне лень его искать.)
sbi

11

В C ++ должен быть способ отличить чисто виртуальную функцию от объявления нормальной виртуальной функции. Они решили использовать = 0синтаксис. Они могли бы просто сделать то же самое, добавив чистое ключевое слово. Но C ++ довольно не хочет добавлять новые ключевые слова и предпочитает использовать другие механизмы для введения функций.


2
-0: когда вам нечего сказать самостоятельно, используйте обширную цитату (см. Ответ Джерри Коффина для +1;)
просто кто-то

7

Ничто не является "инициализированным" или "назначенным" нулем в этом случае. = 0просто синтаксическая конструкция, состоящая из токенов =и 0токенов, которая не имеет абсолютно никакого отношения ни к инициализации, ни к присваиванию.

Это не имеет никакого отношения к какому-либо фактическому значению в «vtable». В языке C ++ нет понятия «vtable» или чего-либо подобного. Различные «vtables» - это не более чем детали конкретных реализаций.


3

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

Я полагаю, что это было упомянуто в Проекте и Развитии C ++ Бьярном Страуструпом.


2

Я бы предположил, что это только часть грамматики C ++. Я не думаю, что есть какие-то ограничения на то, как компиляторы фактически реализуют это для данного конкретного двоичного формата. Вы предположили, что, вероятно, были правы для ранних компиляторов C ++.


2

= 0Объявляет чистую виртуальную функцию .

Понятно, что это инициализирует запись vtable для этой функции в NULL, а любое другое значение приводит к ошибке времени компиляции.

Я не думаю, что это правда. Это просто особый синтаксис. Vtable определяется реализацией. Никто не говорит, что запись vtable для чистого члена должна фактически обнуляться при построении (хотя большинство компиляторов обрабатывают vtables аналогично).


4
Это на самом деле не правда. Нет ничего плохого в том, чтобы дать определение чисто виртуальной функции. Единственное, что = 0делает, - это делает весь класс абстрактным и запрещает виртуальные вызовы чистых функций. Невиртуальные вызовы все еще в порядке, и именно тогда используется определение (если вы его предоставили).
2010 года

Просто посмотрите на вывод Godbolt. Здесь нет места для двусмысленности или спекуляции. Я посмотрю сам позже
Льюис Келси

Кажется, что он заменяет запись на __cxa_pure_virtual arobenko.gitbooks.io/bare_metal_cpp/content/compiler_output/… вместо Base :: f ()
Льюис Келси

1

Ну, вы также можете инициализировать запись vtable, чтобы она указывала на реальную функцию "

 virtual void fun()
 {
     //dostuff()
 }

Кажется интуитивно понятным, что запись vtable может быть определена как нигде (0) или как функция. Если вы укажете свое собственное значение, оно, вероятно, приведет к тому, что оно будет указывать на мусор, а не на функцию. Но именно поэтому «= 0» разрешено, а «= 1» - нет. Я подозреваю, что Нил Баттерворт прав, почему "= 0" вообще используется


1
Даже у меня было похожее мнение, но так как многие цитировали стандарты и комментарии Бьярне по этому поводу, у нас минимальные шансы на спор :)
mukeshkumar
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.