Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Виртуальный метод нельзя удалить в С++ 0x?

Автор вопроса: iammilindОтветов: 5

Сообщение об ошибке, кажется, немного вводит в заблуждение в сценарии, когда мы пытаемся delete использовать virtual метод.

prog.cpp:4:16: error: deleted function 'virtual void Test::foo()'
prog.cpp:8:2: error: used here

Код

struct Test : public Base
{
  Test() {}
  virtual void foo () = delete;  // error
};

Метод virtual не может быть delete по той же причине, почему они не могут оставаться нереализованными в C++03? Есть ли способ упомянуть, что Test намеренно не реализует virtual foo() ?

  • Попробуйте просто указать их как виртуальные без удаления. Yet Another Geek 24.06.2011
  • Вау, я до сих пор никогда не осознавал, что ты можешь это сделать. И, во-вторых, это каким-либо образом полезно или полезно? DumbCoder 24.06.2011
  • @DumbCoder: Ну, ты не можешь. Вы получаете ошибку. Отсюда этот вопрос. Lightness Races in Orbit 24.06.2011
  • Если нам должно быть разрешено вызывать (Base*)->foo(), а Base* может быть Test*, то как мы можем позволить Test не реализовывать foo и не быть абстрактным? Какой смысл удалять функцию из производного класса, которая должна существовать? Kerrek SB 24.06.2011
  • @Tomalak Geret'kal - меня больше интересовало, насколько это полезно и где бы вы его использовали? Надо было сделать это явным. Наверное, пойдет и посмотрит стандартный документ. DumbCoder 24.06.2011
  • Это не имеет никакого смысла. Публичное наследование означает is-a, это фундаментальное требование, чтобы производный класс реализовывал (возможно, переопределял) полный виртуальный интерфейс. Gene Bushuyev 24.06.2011

c++virtualc++11

Ответы

Ответ 1 · рейтинг 9 · David Rodríguez - dribeas

Термин use имеет конкретное определение в стандарте, и, в частности, для виртуальных функций определение odr-used таково:

§3.2/2 (C++0x FDIS) [...] Виртуальная функция-член используется odr, если она не является чистой.[...]

Где odr-used - новый термин в будущем стандарте, который относится к тому, что в предыдущем стандарте называлось просто used:

§3.2/2 (текущий стандарт) [...] Виртуальная функция-член используется, если она не является чистой.[...]

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

Ответ 2 · рейтинг 3 · Lightness Races in Orbit

Все нечистые виртуальные функции должны быть реализованы, используете вы их или нет:

struct Test
{
  Test() {}
  virtual void foo();
};

int main() {
   Test* t = new Test;
   // ^ it seems to have to be dynamic allocation to coerce the error out
}

/* Output:
/home/Y3oGMf/ccOLuYWf.o: In function `main':
prog.cpp:(.text+0x17): undefined reference to `vtable for Test'
collect2: ld returned 1 exit status
*/

Я думаю, вы видите немного странное сообщение об ошибке, касающееся использования удаленной функции по аналогичной причине. Это просто из-за того, как все работает внутри. Более разумное сообщение об ошибке может быть в строке, где вы пытались delete использовать член функции virtual, говоря: "Это не сработает. Это вызовет проблемы, потому что эта реализация должна существовать".

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

Ответ 3 · рейтинг 2 · Muhammad Hasan Khan

Насколько я понимаю, ключевое слово delete предназначено для удаления реализации по умолчанию, созданной компилятором. Для виртуальных методов нет реализации по умолчанию, сгенерированной компилятором.

Ответ 4 · рейтинг 2 · Oktalist

Разрешены удаленные виртуальные функции, но не переопределение их.

§10.3(11) говорит:

Виртуальная функция, объявленная в классе, должна быть определена или объявлена ​​чистой (10.4) в этом классе, или и то, и другое; но диагностика не требуется (3.2).

В §8.4.1 говорится, что удаленная функция определена.

И §10.3(16) говорит:

Функция с удаленным определением (8.4) не должна переопределять функцию, не имеющую удаленного определения. Точно так же функция, не имеющая удаленного определения, не должна переопределять функцию с удаленным определением.

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

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

struct Base {
    virtual void foo();
};
struct Derived : public Base {
    virtual void foo() = delete;
};

Но следующий код правильно сформирован:

struct Base {
    virtual void foo() = delete;
};
struct Derived : public Base {
    virtual void foo() = delete;
};

ДЕМО

У OP была либо ошибка компилятора, либо проблема QoI (трудно сказать, что именно, потому что он не опубликовал весь код), которая с тех пор была исправлена.

Ответ 5 · RedX

Возможно, вам не следует наследовать от класса, который ТРЕБУЕТ что-то, если ваш производный класс не может это реализовать. Вероятно, вам не нужно наследовать от этого класса в первую очередь.

Это все равно, что сказать: "Я делаю лучшую машину. Это своего рода машина, но без колес". Вы уверены, что это машина?

Или ты спрашиваешь это просто из любопытства?

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы