2014-08-31 4 views
0

Я знаю, почему и как работают виртуальные методы, и большую часть времени люди говорят мне, что я всегда должен отмечать метод виртуальным, но я не понимаю, почему, если я не собираюсь его переопределять. И я также знаю, что есть небольшая проблема с памятью.Почему я должен отмечать все методы виртуальными в C++? Есть ли компромисс?

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

Пример кода:

class Point 
{ 
    int x, y; 
    public: 
     virtual void setX(int i); 
     virtual void setY(int i); 
}; 

(Этот вопрос не равен Should I mark all methods virtual?, потому что я хочу знать, компромисс и потому, что язык программирования в случае C++, а не C#)

OBS : Извините, если есть какая-либо грамматическая ошибка, английский не мой родной язык.

+6

Как вам это сказал? «Виртуальные» вызовы функций обычно связаны с просмотром vtable и не могут быть встроены. Если вы им не нужны, не используйте их. – filmor

+0

Проверьте книгу Wrox Professional C++, говорят, что я всегда должен отмечать метод virtual. – 2014-08-31 17:18:00

+3

Не все, что написано в книге, является хорошим советом. Даже если название содержит слово «Профессионал». – celtschk

ответ

5

Нет, вы не должны «отмечать все методы как виртуальные».

Если вы хотите, чтобы метод был виртуальным, отметьте его как таковой. Если нет, оставьте ключевое слово вне.

Существует накладные расходы для виртуальных методов по сравнению с обычными. Если вы хотите больше узнать об этом, ознакомьтесь с частью Википедии около VTables.

2

Это не тот случай, т. Е. Если вам не нужна виртуальная функция, то не используйте ее. Кроме того, в соответствии с Бьярне СтрауструпPay per use

В C++: -

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

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

  3. Классы с виртуальными функциями, как правило, предназначены для унаследованных. Производные классы могут заменить некоторые, все или ни одна из виртуальных функций . Это может создать дополнительную сложность, а сложность - программисты смертельного врага. Например, производный класс может плохо реализовать виртуальную функцию. Это может сломать часть базового класса, которая полагается на виртуальную функцию.

1

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

1

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

+0

Принцип, который вы упомянули, является одним из * языкового дизайна *, и это более точно указано как «дон», t платить за то, что вы не используете *. Программист может все же решить всегда использовать некоторую функцию; этот ответ не дает веских оснований не использовать виртуальные функции IMHO. – delnan

3

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

Совет, чтобы все функции-члены виртуального в целом означает, что либо:

  1. люди, дающие советы не понимают класс, или
  2. люди, дающие советы не понимают дизайн OO.

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

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

+0

+1 потому что он выделяет центральную точку. Эффективные штрафы являются лишь побочным эффектом плохого дизайна класса. –

0

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

Действительно, существует шаблон для обеспечения пред/постусловий, который явно требует, чтобы публичные члены были не виртуальных. Она работает следующим образом:

class Whatever 
{ 
public: 
    int frobnicate(int); 
protected: 
    virtual int do_frobnicate(int); 
}; 

int Whatever::frobnicate(int x) 
{ 
    check_preconditions(x); 
    int result = do_frobnicate(x); 
    check_postconditions(x, result); 
    return result; 
} 

Поскольку производные классы не могут переопределить публичную функцию, они не могут удалить предварительные проверки/Постусловие. Однако они могут переопределить защищенный do_frobnicate, который выполняет фактическую работу.

+0

Вы должны сделать виртуальную функцию 'private', а не' protected', хотя я знаю одного (но только одного) гуру C++, который думает иначе. Кстати, Херб Саттер однажды назвал этот шаблон «Инициалом не виртуального интерфейса»: http://www.gotw.ca/publications/mill18.htm –