Сообщение об ошибке, кажется, немного вводит в заблуждение в сценарии, когда мы пытаемся 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
Термин 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
Возможно, вам не следует наследовать от класса, который ТРЕБУЕТ что-то, если ваш производный класс не может это реализовать. Вероятно, вам не нужно наследовать от этого класса в первую очередь.
Это все равно, что сказать: "Я делаю лучшую машину. Это своего рода машина, но без колес". Вы уверены, что это машина?