Мысли о разных типах наследования

Если посмотреть на следующий простой код, имеет смысл ввести виртуальный деструктор, если я знаю, что мы не удаляем его из базового указателя? Кажется, что мы должны стараться избегать vtable look ups, если это возможно по соображениям производительности. Я понимаю о преждевременной оптимизации и т.д., Но это всего лишь вопрос в целом. Мне было интересно, что вы думаете о следующем:

  • используя защищенный деструктор, если мы не удаляем элементы через базовый указатель
  • накладные расходы, связанные с внедрением единого виртуального метода

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

class CardPlayer
{
 public:
 typedef std::vector<cardplayer> CollectionType;

 explicit CardPlayer()=default;

 explicit CardPlayer(const Card::CollectionType& cards);
 explicit CardPlayer(Card::CollectionType&& cards);

 void receiveCard(const Card& card);

 bool discardCard(Card&& card);
 void foldCards();

 inline const Card::CollectionType& getCards() { return cards_; }
 // virtual ~CardPlayer() = default; // should we introduce vtable if not really needed?
 protected:
 ~CardPlayer()=default;
 Card::CollectionType cards_;
};
--------------------------------------------------------------------
#include "CardPlayer.h"
#include <functional>

class BlackJackPlayer : public CardPlayer
{
 public:
 typedef std::vector<blackjackplayer> CollectionType;
 typedef std::function<bool(const card::collectiontype&)=""> hitFnType;

 BlackJackPlayer(hitFnType fn) : hitFn_(fn) {}

 bool wantHit() 
 {
 return hitFn_(getCards());
 }

 hitFnType hitFn_;
};
</bool(const></blackjackplayer></functional></cardplayer>
3 ответа

Я бы избегал виртуального деструктора и, следовательно, добавлял vtbl в класс в вашем случае. Вы можете защитить класс от его удаления с помощью указателя базового класса, поэтому кажется, что без каких-либо других виртуальных методов это было бы преждевременным пессимизацией :)

Кроме того, наличие еще одного указателя на экземпляр (vtbl) может складываться в больших проектах. Производительность часто зависит от доступа к памяти, и поэтому вы должны как можно меньше сохранить размер объекта, а также ваши шаблоны доступа к памяти как можно более локальными. Vtbl будет находиться в другом месте памяти и в худшем случае вы попросите процессор прочитать другую строку кэша только для удаления объекта.

Чтобы ответить на другой вопрос, который у вас был: только виртуальные методы маршрутизируются через vtbl, все не виртуальные вызовы не отображаются.


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

В общем, только публичные методы или методы, вызываемые другими методами в базовом классе, должны быть виртуальными. Защищенные методы должны быть виртуальными, если они вызываются из других методов в классе.


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

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

licensed under cc by-sa 3.0 with attribution.