При каких обстоятельствах выгодно давать реализацию чисто виртуальной функции? - PullRequest
28 голосов
/ 10 июня 2009

В C ++ допустимо давать реализацию чисто виртуальной функции:

class C
{
public:
  virtual int f() = 0;
};

int C::f() 
{
  return 0;
}

Зачем вам это нужно?

Связанный вопрос: C ++ faq lite содержит пример:

class Funct {
public:
  virtual int doit(int x) = 0;
  virtual ~Funct() = 0;
};

inline Funct::~Funct() { }  // defined even though it's pure virtual; it's faster this way; trust me

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

Ответы [ 6 ]

23 голосов
/ 10 июня 2009

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

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

void Derived::f()
{
    Base::f();

    // Other Derived specific functionality
}

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

4 голосов
/ 11 июня 2009

Только что узнал, что Херб Саттер ответил на первую часть этого вопроса в своем Гуру недели # 31 .

4 голосов
/ 10 июня 2009

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

Таким образом, производный класс реализует виртуальную функцию и вызывает базовую базовую версию:

class X: public C
{
    public:
        virtual int f()
        {
            return C::f() + 1; // I am +1 over my parent.
        }
};
2 голосов
/ 10 июня 2009

G'day,

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

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

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

Ах, только что увидел пост @Martin York, в котором приведен пример.

На самом деле, Скотт Мейерс обсуждает это в своей книге «Эффективный C ++». Это пункт 36 в 1-м издании.

НТН

ура

0 голосов
/ 11 июня 2009

Что касается скорости виртуального деструктора, то это потому, что деструктор определяется в файле cpp, а не в заголовке. Это больше связано с размером, чем со скоростью. Это подробно объясняется в "Крупномасштабном программном обеспечении C ++". К сожалению, я не могу вспомнить все детали, но я думаю, что встроенные виртуальные функции определяются несколько раз в vtable.

Здесь обсуждается это: Действительно ли встроенные виртуальные функции не имеют смысла?

0 голосов
/ 10 июня 2009

Потому что он считается плохо сформированным для записи:

class Funct {
public:
  virtual int doit(int x) = 0;
  virtual ~Funct() = 0 {};
};

Деструктор будет по-прежнему вызываться, если вы наследуете этот класс. Объявление всех методов чисто виртуальными просто для ясности. С таким же успехом вы можете написать это так:

class Funct {
public:
  virtual int doit(int x) = 0;
  virtual ~Funct() {};
};

Класс по-прежнему будет абстрактным, поскольку хотя бы один метод является чисто виртуальным. Деструктор также по-прежнему встроен.

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