Вот класс с неопределенным методом. Кажется, что компиляторы позволяют создавать экземпляры этого класса, если неопределенная функция-член никогда не вызывается:
struct A {
void foo();
};
int main() {
A a; // <-- Works in both VC2013 and g++
a.foo(); // <-- Error in both VC2013 and g++
}
Вот похожая ситуация, но та, которая связана с наследованием. Подкласс Bar
расширяет базовый класс Foo
, Foo
определяет метод g()
, Bar
объявляет метод с тем же именем, но не определяет его:
#include <iostream>
struct Foo {
void g() { std::cout << "g\n"; }
};
struct Bar : Foo {
void g();
};
int main() {
Bar b; // Works in both VC2013 and g++
b.Foo::g(); // Works in both VC2013 and g++
b.g(); // Error in both VC2013 and g++
}
Вот вариант выше. Единственная разница здесь в том, что g()
является virtual
как для Foo
а также Bar
:
#include <iostream>
struct Foo {
virtual void g() { std::cout << "g\n"; }
};
struct Bar : Foo {
virtual void g();
};
int main() {
Bar b; // Works in g++. But not in VC2013, which gives
// 'fatal error LNK1120: 1 unresolved externals'
b.Foo::g(); // Works in g++, but VC2013 already failed on b's construction
b.g(); // Error in g++, but VC2013 already failed on b's construction
}
См. Комментарии к коду для сравнения различий в поведении между VC2013 и g ++.
virtual
Ключевое слово по сравнению с тем в его версии без virtual
ключевое слово?Bar
В декларации g()
считаться первостепеннымBar
не дает определения?Какой компилятор правильный, если есть?
Они оба правы. Ваш код неверен, диагностика не требуется. [Class.virtual] / 11
[Intro.compliance] / 2:Виртуальная функция, объявленная в классе, должна быть определена или объявлена
чистый (10,4) в этом классе или оба; но никакой диагностики не требуется
(3.2).
Если программа содержит нарушение правила, для которого нет диагностики
Этот международный стандарт не требует
реализации в отношении этой программы.
Посмотрите ваши настройки оптимизации для GCC, они могут влиять на поведение.
Всегда разрешены неиспользованные неопределенные методы?
Функция-член должна быть определена тогда и только тогда, когда она используется в odr. [Basic.def.odr] / 3:
Каждая программа должна содержать ровно одно определение каждого не встроенного
функция или переменная, которая используется в этой программе; нет диагностики
требуется.
Теперь рассмотрим [basic.def.odr] / 2:
Выражение потенциально оценивается если это не оцененный операнд (пункт 5) или его подвыражение.
[…] Виртуальная функция-член используется odr, если она не является чистой.
Неперегруженная функция, имя которой отображается в виде потенциально оцененного выражения или члена набора функций-кандидатов, если она выбрана разрешением перегрузки при обращении к потенциально оцененному выражению, используется odr, если только она не является чисто виртуальной Функция и ее имя явно не определены.
Вы по-прежнему можете использовать неопределенные не виртуальные функции-члены внутри decltype
или же sizeof
, Но не чистые виртуальные функции используются odr просто потому, что они не чистые.
Является ли объявление Bar в g () переопределением, даже если Bar
не дает определения?
Да.